Skip to content

Commit

Permalink
feat: ✨ add qq platform (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
Aimerny authored Jul 8, 2024
1 parent 303831a commit 3a664ea
Show file tree
Hide file tree
Showing 13 changed files with 449 additions and 3 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.5.0</version>
</dependency>
</dependencies>

<build>
Expand Down
72 changes: 71 additions & 1 deletion readme-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[English](readme.md)

[![License](https://shields.io/github/license/AnzhiZhang/ChatHub?label=License)](https://github.com/AnzhiZhang/ChatHub/blob/master/LICENSE)
[![Modrith](https://img.shields.io/modrinth/v/H3USaks7?logo=modrinth&label=Modrinth&color=%2300AF5C)](https://modrinth.com/plugin/chathub)
[![CurseForge](https://cf.way2muchnoise.eu/short_825508_downloads.svg)](https://www.curseforge.com/minecraft/bukkit-plugins/chathub)
[![Release](https://shields.io/github/v/release/AnzhiZhang/ChatHub?display_name=tag&include_prereleases&label=Release)](https://github.com/AnzhiZhang/ChatHub/releases/latest)
[![Gitmoji](https://img.shields.io/badge/gitmoji-%20😜%20😍-FFDD67.svg)](https://gitmoji.dev/)
Expand Down Expand Up @@ -259,10 +260,79 @@ Kook 消息的格式化文本。占位符与上文同理,所有的服务器名

### qq

> 如需要此功能,欢迎 PR。
> [!NOTE]
> `list` 指令暂未支持
该功能为双向转发,即 MC 内消息会发送到指定 QQ 群,QQ 群内消息将被转发到 MC 内。

#### enable

默认值:`false`

是否启用 [QQ](https://im.qq.com/index) 转发。

#### groupId

QQ 群 ID。

### qq.api

#### host

Default: `0.0.0.0`

OneBot 配置的反向 WebSocket 服务地址

#### wsReversePort

Default: `9001`

OneBot 配置的反向 WebSocket 服务端口

#### wsReversePath

Default: `/ws/`

websocket资源路径

> 这里是一个 OneBot 的反向 WebSocket 配置示例: `ws://127.0.0.1:9001/ws/`
### qq.message

QQ 消息的格式化文本。占位符与上文同理,所有的服务器名称会自动转为 plain 格式,您无需使用 plain 格式的占位符。

#### chat

默认值:`[{server}] <{name}>: {message}`

聊天消息。

#### join

默认值:`[+] [{server}] {name}`

玩家加入服务器消息。

#### leave

默认值:`[-] {name}`

玩家离开服务器消息。

#### switch

默认值:`<{name}>: [{serverFrom}] ➟ [{serverTo}]`

玩家切换服务器消息。

#### list

默认值:`- [{server}] 当前共有{count}名玩家在线: {playerList}`

`/list` 指令显示的消息。

#### listEmpty

默认值:`当前没有玩家在线`

使用 `/list` 指令且玩家列表为空时显示的消息。
71 changes: 70 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,79 @@ Message for `/list` command when player list is empty.

### qq

> In case if you need this feature, PR is welcomed.
> [!NOTE]
> The `list` command is not currently available.
The messages from the group will be synchronized to ChatHub and chatHub will forward all public messages to the group.

#### enable

Default: `false`

Enable [QQ](https://im.qq.com/index) forwaring.

#### groupId

Group ID.

### qq.api

#### host

Default: `0.0.0.0`

OneBot server’s reverse webSocket host

#### wsReversePort

Default: `9001`

OneBot server’s reverse webSocket port

#### wsReversePath

Default: `/ws/`

Websocket resource location.

> Here is a demo for one bot ws reverse path configuration: `ws://127.0.0.1:9001/ws/`
### qq.message

QQ message format sages. Placeholders are defined same as Miencraft, all server name will auto translate to plain format, you do not have to use plain placeholders.

#### chat

Default: `[{server}] <{name}>: {message}`

Chat.

#### join

Default: `[+] [{server}] {name}`

Message when player joined the server.

#### leave

Default: `[-] {name}`

Message when player left the server.

#### switch

Default: `<{name}>: [{serverFrom}] ➟ [{serverTo}]`

Message when player switched server.

#### list

Default: `- [{server}] 当前共有{count}名玩家在线: {playerList}`

Message for `/list` command.

#### listEmpty

Default: `当前没有玩家在线`

Message for `/list` command when player list is empty.
6 changes: 6 additions & 0 deletions src/main/java/com/zhanganzhi/chathub/core/EventHub.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.zhanganzhi.chathub.platforms.Platform;
import com.zhanganzhi.chathub.platforms.discord.DiscordAdaptor;
import com.zhanganzhi.chathub.platforms.kook.KookAdaptor;
import com.zhanganzhi.chathub.platforms.qq.QQAdaptor;
import com.zhanganzhi.chathub.platforms.velocity.VelocityAdaptor;

import java.util.ArrayList;
Expand All @@ -34,6 +35,11 @@ public EventHub(ChatHub chatHub) {
if (config.isKookEnabled()) {
adaptors.add(new KookAdaptor(chatHub));
}

// qq
if (config.isQQEnabled()) {
adaptors.add(new QQAdaptor(chatHub));
}
}

public IAdaptor<? extends IFormatter> getAdaptor(Platform platform) {
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/com/zhanganzhi/chathub/core/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,24 @@ public Long getKookDaemonInterval() {
public Long getKookDaemonRetry() {
return configToml.getLong("kook.daemon.retry");
}

public boolean isQQEnabled() {
return configToml.getBoolean("qq.enable");
}

public String getQQGroupId() {
return configToml.getString("qq.groupId");
}

public String getQQHost() {
return configToml.getString("qq.api.host");
}

public Long getQQWsReversePort() {
return configToml.getLong("qq.api.wsReversePort");
}

public String getQQWsReversePath() {
return configToml.getString("qq.api.wsReversePath", "");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
public enum Platform {
DISCORD("discord"),
KOOK("kook"),
QQ("qq"),
VELOCITY("velocity", "minecraft");

private final String name;
Expand Down
91 changes: 91 additions & 0 deletions src/main/java/com/zhanganzhi/chathub/platforms/qq/QQAdaptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.zhanganzhi.chathub.platforms.qq;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.zhanganzhi.chathub.ChatHub;
import com.zhanganzhi.chathub.core.adaptor.AbstractAdaptor;
import com.zhanganzhi.chathub.core.events.MessageEvent;
import com.zhanganzhi.chathub.platforms.Platform;
import com.zhanganzhi.chathub.platforms.qq.dto.QQEvent;
import com.zhanganzhi.chathub.platforms.qq.protocol.QQAPI;

import java.util.ArrayList;
import java.util.List;

public class QQAdaptor extends AbstractAdaptor<QQFormatter> {
private final QQAPI qqAPI;
private final Thread eventListener;
private boolean listenerStopFlag = false;

public QQAdaptor(ChatHub chatHub) {
super(chatHub, Platform.QQ, new QQFormatter());
qqAPI = new QQAPI(chatHub);
eventListener = new Thread(this::eventListener, "qq-event-listener");
}

@Override
public void start() {
chatHub.getLogger().info("QQ enabled");
qqAPI.start();
eventListener.start();
}

@Override
public void stop() {
// stop listener
listenerStopFlag = true;

// interrupt listener, clear event queue
if (eventListener != null) {
eventListener.interrupt();
}

// close ws server
qqAPI.stop();
}

@Override
public void sendPublicMessage(String message) {
new Thread(() -> qqAPI.sendMessage(message, config.getQQGroupId())).start();
}

public void eventListener() {
while (!listenerStopFlag) {
consumeEvent();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
if (listenerStopFlag) {
// clear other event
consumeEvent();
break;
}
}
}
}

public void consumeEvent() {
QQEvent curEvent;
while ((curEvent = qqAPI.getQqEventQueue().poll()) != null) {
if (
"message".equals(curEvent.getPostType())
&& "group".equals(curEvent.getMessageType())
&& "array".equals(curEvent.getMessageFormat())
&& config.getQQGroupId().equals(curEvent.getGroupId().toString())
) {
JSONArray message = curEvent.getMessage();
List<String> messages = new ArrayList<>();
for (int i = 0; i < message.size(); i++) {
JSONObject part = message.getJSONObject(i);
if (part.getString("type").equals("text")) {
messages.add(part.getJSONObject("data").getString("text"));
}
}
String content = String.join(" ", messages);
chatHub.getEventHub().onUserChat(new MessageEvent(
Platform.QQ, null, curEvent.getSender().getNickname(), content
));
}
}
}
}
16 changes: 16 additions & 0 deletions src/main/java/com/zhanganzhi/chathub/platforms/qq/QQFormatter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.zhanganzhi.chathub.platforms.qq;

import com.zhanganzhi.chathub.core.formatter.AbstractFormatter;
import com.zhanganzhi.chathub.core.formatter.FormattingContent;
import com.zhanganzhi.chathub.platforms.Platform;

public class QQFormatter extends AbstractFormatter {
protected QQFormatter() {
super(Platform.QQ);
}

@Override
protected String replaceAll(String message, FormattingContent content) {
return getPlainString(super.replaceAll(message, content));
}
}
21 changes: 21 additions & 0 deletions src/main/java/com/zhanganzhi/chathub/platforms/qq/dto/QQEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.zhanganzhi.chathub.platforms.qq.dto;

import com.alibaba.fastjson2.JSONArray;
import lombok.Data;

@Data
public class QQEvent {
private Long selfId;
private Long messageId;
private Long realId;
private Long groupId;
private Long time;
private String postType;
private String metaEventType;
private String messageType;
private Sender sender;
private String rawMessage;
private String subType;
private JSONArray message;
private String messageFormat;
}
11 changes: 11 additions & 0 deletions src/main/java/com/zhanganzhi/chathub/platforms/qq/dto/Sender.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.zhanganzhi.chathub.platforms.qq.dto;

import lombok.Data;

@Data
public class Sender {
private Long userId;
private String nickname;
private String card;
private String role;
}
Loading

0 comments on commit 3a664ea

Please sign in to comment.