diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index e849a6f4..9d55a6c6 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,28 +1,28 @@
---
name: Bug report
about: Create a report to help us improve
-title: '提交之前请查看是否有相关 issue,谢谢。'
+title: 'Please check if there are similar issues before submitting'
labels: ''
assignees: ''
---
-**Bug 描述**
+**Bug Description**
A clear and concise description of what the bug is.
-**复现**
-复现步骤:
+**Reproduce**
+step:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
-**预期结果**
+**Expected results**
A clear and concise description of what you expected to happen.
-**截图**
+**Screenshot**
If applicable, add screenshots to help explain your problem.
-**附加信息**
+**Additional Information**
Add any other context about the problem here.
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
new file mode 100644
index 00000000..26ac135c
--- /dev/null
+++ b/.github/workflows/maven.yml
@@ -0,0 +1,21 @@
+# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
+# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven
+
+# This workflow uses actions that are not certified by GitHub.
+# They are provided by a third-party and are governed by
+# separate terms of service, privacy policy, and support
+# documentation.
+
+name: Java CI with Maven
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ branches: [ "master" ]
+
+jobs:
+ build:
+ uses: ./.github/workflows/reusable_run_tests.yml
+ secrets:
+ codecov_token: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.github/workflows/reusable_run_tests.yml b/.github/workflows/reusable_run_tests.yml
new file mode 100644
index 00000000..42ce8c34
--- /dev/null
+++ b/.github/workflows/reusable_run_tests.yml
@@ -0,0 +1,29 @@
+name: A reusable workflow to build and run the unit test suite
+
+on:
+ workflow_call:
+ secrets:
+ codecov_token:
+ required: true
+ workflow_dispatch:
+
+jobs:
+ build_and_test:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+ cache: maven
+ - name: Build with Maven
+ run: mvn -B package --file pom.xml
+ - name: Upload coverage reports to Codecov
+ uses: codecov/codecov-action@v4
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ verbose: true
\ No newline at end of file
diff --git a/README.md b/README.md
index fc4a8938..c069c84e 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
+[](https://codecov.io/gh/crossoverJie/cim)
[](https://github.com/crossoverJie/cim)
[](https://juejin.im/post/5c2bffdc51882509181395d7)
@@ -16,27 +17,26 @@
# V2.0
- [x] Upgrade to JDK17 & springboot3.0
+- [x] Client SDK
- [ ] Client use [picocli](https://picocli.info/) instead of springboot.
-- [ ] Supports binary client(build with golang).
-- [ ] Support integration testing.
+- [x] Support integration testing.
- [ ] Integrate OpenTelemetry .
- [ ] Support single node startup(Contains no components).
- [ ] Third-party components support replacement(Redis/Zookeeper, etc.).
- [ ] Support web client(websocket).
- [ ] Support docker container.
- [ ] Support kubernetes operation.
+- [ ] Supports binary client(build with golang).
-## 介绍
+## Introduction
-`CIM(CROSS-IM)` 一款面向开发者的 `IM(即时通讯)`系统;同时提供了一些组件帮助开发者构建一款属于自己可水平扩展的 `IM` 。
+`CIM(CROSS-IM)` is an `IM (instant messaging)` system for developers; it also provides some components to help developers build their own scalable `IM`.
+Using `CIM`, you can achieve the following requirements:
+- `IM` instant messaging system.
+- Message push middleware for `APP`.
+- Message middleware for `IOT` massive connection scenarios.
-借助 `CIM` 你可以实现以下需求:
-
-- `IM` 即时通讯系统。
-- 适用于 `APP` 的消息推送中间件。
-- `IOT` 海量连接场景中的消息透传中间件。
-
-> 在使用或开发过程中有任何疑问都可[联系我](#联系作者)。
+> If you have any questions during use or development, you can [contact me](#联系作者).
## 视频演示
@@ -47,6 +47,7 @@
| [群聊](https://youtu.be/_9a4lIkQ5_o) [私聊](https://youtu.be/kfEfQFPLBTQ) | [群聊](https://www.bilibili.com/video/av39405501) [私聊](https://www.bilibili.com/video/av39405821) |
|
|
+
## TODO LIST
@@ -60,45 +61,46 @@
* [x] 服务端自动剔除离线客户端
* [x] 客户端自动重连
* [x] [延时消息](#延时消息)
+* [x] SDK 开发包
* [ ] 分组群聊
-* [ ] SDK 开发包
* [ ] 离线消息
-* [ ] 协议支持消息加密
+* [ ] 消息加密
-## 系统架构
+## Architecture
-
+
-- `CIM` 中的各个组件均采用 `SpringBoot` 构建。
-- 采用 `Netty` 构建底层通信。
-- `Redis` 存放各个客户端的路由信息、账号信息、在线状态等。
-- `Zookeeper` 用于 `IM-server` 服务的注册与发现。
+- Each component in `CIM` is built using `SpringBoot`
+ - Client build with [cim-client-sdk](https://github.com/crossoverJie/cim/tree/master/cim-client-sdk)
+- Use `Netty` to build the underlying communication.
+- `MetaStore` is used for registration and discovery of `IM-server` services.
### cim-server
+IM server is used to receive client connections, message forwarding, message push, etc.
+Support cluster deployment.
-`IM` 服务端;用于接收 `client` 连接、消息透传、消息推送等功能。
-
-**支持集群部署。**
+### cim-route
-### cim-forward-route
-
-消息路由服务器;用于处理消息路由、消息转发、用户登录、用户下线以及一些运营工具(获取在线用户数等)。
+Route server; used to process message routing, message forwarding, user login, user offline, and some operation tools (get the number of online users, etc.).
### cim-client
+IM client terminal, a command can be started and initiated to communicate with others (group chat, private chat).
-`IM` 客户端;给用户使用的消息终端,一个命令即可启动并向其他人发起通讯(群聊、私聊)。
-
-## 流程图
+## Flow Chart
-
+
-- 客户端向 `route` 发起登录。
-- 登录成功从 `Zookeeper` 中选择可用 `IM-server` 返回给客户端,并保存登录、路由信息到 `Redis`。
-- 客户端向 `IM-server` 发起长连接,成功后保持心跳。
-- 客户端下线时通过 `route` 清除状态信息。
+- Server register to `MetaStore`
+- Route subscribe `MetaStore`
+- Client login to Route
+ - Route get Server info from `MetaStore`
+- Client open connection to Server
+- Client1 send message to Route
+- Route select Server and forward message to Server
+- Server push message to Client2
## 快速启动
@@ -106,14 +108,16 @@
首先需要安装 `Zookeeper、Redis` 并保证网络通畅。
```shell
-docker run --name zookeeper -d -p 2181:2181 zookeeper
-docker run --rm --name redis -d -p 6379:6379 redis
+docker run --rm --name zookeeper -d -p 2181:2181 zookeeper:3.9.2
+docker run --rm --name redis -d -p 6379:6379 redis:7.4.0
```
```shell
git clone https://github.com/crossoverJie/cim.git
cd cim
-mvn -Dmaven.test.skip=true clean package
+mvn clean package -DskipTests=true
+cd cim-server && cim-client && cim-forward-route
+mvn clean package spring-boot:repackage -DskipTests=true
```
### 部署 IM-server(cim-server)
@@ -272,7 +276,7 @@ java -jar cim-client-1.0.0-SNAPSHOT.jar --server.port=8084 --cim.user.id=上方
:delay delayMsg 10
```
-
+
## 联系作者
diff --git a/cim-client-sdk/README.md b/cim-client-sdk/README.md
new file mode 100644
index 00000000..bac1d54c
--- /dev/null
+++ b/cim-client-sdk/README.md
@@ -0,0 +1,25 @@
+
+```java
+ var auth1 = ClientConfigurationData.Auth.builder()
+ .userId(id)
+ .userName(cj)
+ .build();
+
+ Client client1 = Client.builder()
+ .auth(auth1)
+ .routeUrl(routeUrl)
+ .build();
+
+ ClientState.State state = client1.getState();
+ Awaitility.await().atMost(10, TimeUnit.SECONDS)
+ .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, state));
+ Optional serverInfo = client1.getServerInfo();
+ Assertions.assertTrue(serverInfo.isPresent());
+
+ // send msg
+ String msg = "hello";
+ client1.sendGroup(msg);
+
+ // get oline user
+ Set onlineUser = client1.getOnlineUser();
+```
\ No newline at end of file
diff --git a/cim-client-sdk/pom.xml b/cim-client-sdk/pom.xml
new file mode 100644
index 00000000..8d353a39
--- /dev/null
+++ b/cim-client-sdk/pom.xml
@@ -0,0 +1,51 @@
+
+
+ 4.0.0
+
+ com.crossoverjie.netty
+ cim
+ 1.0.0-SNAPSHOT
+
+
+ cim-client-sdk
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+
+ com.crossoverjie.netty
+ cim-common
+
+
+
+ com.crossoverjie.netty
+ cim-rout-api
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+
+ org.junit.vintage
+ junit-vintage-engine
+ test
+
+
+ com.crossoverjie.netty
+ cim-integration-test
+ ${project.version}
+ test
+
+
+
+
\ No newline at end of file
diff --git a/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/Client.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/Client.java
new file mode 100644
index 00000000..c83ad281
--- /dev/null
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/Client.java
@@ -0,0 +1,39 @@
+package com.crossoverjie.cim.client.sdk;
+
+import com.crossoverjie.cim.client.sdk.impl.ClientBuilderImpl;
+import com.crossoverjie.cim.client.sdk.impl.ClientConfigurationData;
+import com.crossoverjie.cim.common.pojo.CIMUserInfo;
+import com.crossoverjie.cim.route.api.vo.req.P2PReqVO;
+import com.crossoverjie.cim.route.api.vo.res.CIMServerResVO;
+import java.io.Closeable;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+
+public interface Client extends Closeable {
+
+ static ClientBuilder builder() {
+ return new ClientBuilderImpl();
+ }
+
+ default void sendP2P(P2PReqVO p2PReqVO) throws Exception{
+ sendP2PAsync(p2PReqVO).get();
+ };
+
+ CompletableFuture sendP2PAsync(P2PReqVO p2PReqVO);
+
+ default void sendGroup(String msg) throws Exception{
+ sendGroupAsync(msg).get();
+ };
+
+ CompletableFuture sendGroupAsync(String msg);
+
+ ClientState.State getState();
+
+ ClientConfigurationData.Auth getAuth();
+
+ Set getOnlineUser() throws Exception;
+
+ Optional getServerInfo();
+
+}
diff --git a/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/ClientBuilder.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/ClientBuilder.java
new file mode 100644
index 00000000..783b3b3c
--- /dev/null
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/ClientBuilder.java
@@ -0,0 +1,26 @@
+package com.crossoverjie.cim.client.sdk;
+
+import com.crossoverjie.cim.client.sdk.impl.ClientConfigurationData;
+import com.crossoverjie.cim.client.sdk.io.MessageListener;
+import com.crossoverjie.cim.client.sdk.io.ReconnectCheck;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import com.crossoverjie.cim.client.sdk.io.backoff.BackoffStrategy;
+import okhttp3.OkHttpClient;
+
+/**
+ * @author crossoverJie
+ */
+public interface ClientBuilder {
+
+ Client build();
+ ClientBuilder auth(ClientConfigurationData.Auth auth);
+ ClientBuilder routeUrl(String routeUrl);
+ ClientBuilder loginRetryCount(int loginRetryCount);
+ ClientBuilder event(Event event);
+ ClientBuilder reconnectCheck(ReconnectCheck reconnectCheck);
+ ClientBuilder okHttpClient(OkHttpClient okHttpClient);
+ ClientBuilder messageListener(MessageListener messageListener);
+ ClientBuilder callbackThreadPool(ThreadPoolExecutor callbackThreadPool);
+ ClientBuilder backoffStrategy(BackoffStrategy backoffStrategy);
+}
diff --git a/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/ClientState.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/ClientState.java
new file mode 100644
index 00000000..7a953732
--- /dev/null
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/ClientState.java
@@ -0,0 +1,23 @@
+package com.crossoverjie.cim.client.sdk;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+public abstract class ClientState {
+
+ private static final AtomicReference STATE = new AtomicReference<>(State.Initialized);
+
+ public enum State {
+ /**
+ * Client state
+ */
+ Initialized, Reconnecting, Ready, Closed, Failed
+ }
+
+ public void setState(State s) {
+ STATE.set(s);
+ }
+
+ public State getState() {
+ return STATE.get();
+ }
+}
diff --git a/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/Event.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/Event.java
new file mode 100644
index 00000000..f2d3378d
--- /dev/null
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/Event.java
@@ -0,0 +1,36 @@
+package com.crossoverjie.cim.client.sdk;
+
+public interface Event {
+ void debug(String msg, Object... replace);
+ void info(String msg, Object... replace);
+ void warn(String msg, Object... replace);
+ void error(String msg, Object... replace);
+ void fatal(Client client);
+
+ class DefaultEvent implements Event {
+ @Override
+ public void debug(String msg, Object... replace) {
+ System.out.println(msg);
+ }
+
+ @Override
+ public void info(String msg, Object... replace) {
+ System.out.println(msg);
+ }
+
+ @Override
+ public void warn(String msg, Object... replace) {
+ System.out.println(msg);
+ }
+
+ @Override
+ public void error(String msg, Object... replace) {
+ System.err.println(msg);
+ }
+
+ @Override
+ public void fatal(Client client) {
+
+ }
+ }
+}
diff --git a/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/ReConnectManager.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/ReConnectManager.java
new file mode 100644
index 00000000..1db4876e
--- /dev/null
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/ReConnectManager.java
@@ -0,0 +1,69 @@
+package com.crossoverjie.cim.client.sdk;
+
+import com.crossoverjie.cim.client.sdk.impl.ClientImpl;
+import com.crossoverjie.cim.common.kit.HeartBeatHandler;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import io.netty.channel.ChannelHandlerContext;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+public final class ReConnectManager {
+
+ private ScheduledExecutorService scheduledExecutorService;
+
+ /**
+ * Trigger reconnect job
+ *
+ * @param ctx
+ */
+ public void reConnect(ChannelHandlerContext ctx) {
+ buildExecutor();
+ scheduledExecutorService.scheduleAtFixedRate(() -> {
+ try {
+ ClientImpl.getClient().getHeartBeatHandler().process(ctx);
+ } catch (Exception e) {
+ ClientImpl.getClient().getConf().getEvent().error("ReConnectManager reConnect error", e);
+ }
+ },
+ 0, 10, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Close reconnect job if reconnect success.
+ */
+ public void reConnectSuccess() {
+ scheduledExecutorService.shutdown();
+ }
+
+
+ /***
+ * build a thread executor
+ */
+ private void buildExecutor() {
+ if (scheduledExecutorService == null || scheduledExecutorService.isShutdown()) {
+ ThreadFactory factory = new ThreadFactoryBuilder()
+ .setNameFormat("reConnect-job-%d")
+ .setDaemon(true)
+ .build();
+ scheduledExecutorService = new ScheduledThreadPoolExecutor(1, factory);
+ }
+ }
+
+ private static class ClientHeartBeatHandle implements HeartBeatHandler {
+
+ @Override
+ public void process(ChannelHandlerContext ctx) throws Exception {
+ ClientImpl.getClient().reconnect();
+ }
+ }
+
+ public static ReConnectManager createReConnectManager() {
+ return new ReConnectManager();
+ }
+
+ public static HeartBeatHandler createHeartBeatHandler() {
+ return new ClientHeartBeatHandle();
+ }
+}
diff --git a/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/RouteManager.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/RouteManager.java
new file mode 100644
index 00000000..dd896857
--- /dev/null
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/RouteManager.java
@@ -0,0 +1,81 @@
+package com.crossoverjie.cim.client.sdk;
+
+import com.crossoverjie.cim.client.sdk.impl.ClientImpl;
+import com.crossoverjie.cim.common.core.proxy.RpcProxyManager;
+import com.crossoverjie.cim.common.enums.StatusEnum;
+import com.crossoverjie.cim.common.exception.CIMException;
+import com.crossoverjie.cim.common.pojo.CIMUserInfo;
+import com.crossoverjie.cim.common.res.BaseResponse;
+import com.crossoverjie.cim.common.res.NULLBody;
+import com.crossoverjie.cim.route.api.RouteApi;
+import com.crossoverjie.cim.route.api.vo.req.ChatReqVO;
+import com.crossoverjie.cim.route.api.vo.req.LoginReqVO;
+import com.crossoverjie.cim.route.api.vo.req.P2PReqVO;
+import com.crossoverjie.cim.route.api.vo.res.CIMServerResVO;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import okhttp3.OkHttpClient;
+
+public class RouteManager {
+
+
+ private final RouteApi routeApi;
+ private final Event event;
+
+ public RouteManager(String routeUrl, OkHttpClient okHttpClient, Event event) {
+ routeApi = RpcProxyManager.create(RouteApi.class, routeUrl, okHttpClient);
+ this.event = event;
+ }
+
+ public CIMServerResVO getServer(LoginReqVO loginReqVO) throws Exception {
+ BaseResponse cimServerResVO = routeApi.login(loginReqVO);
+
+ // repeat fail
+ if (!cimServerResVO.getCode().equals(StatusEnum.SUCCESS.getCode())) {
+ event.info(cimServerResVO.getMessage());
+
+ // when client in Reconnecting state, could exit.
+ if (ClientImpl.getClient().getState() == ClientState.State.Reconnecting) {
+ event.warn("###{}###", StatusEnum.RECONNECT_FAIL.getMessage());
+ throw new CIMException(StatusEnum.RECONNECT_FAIL);
+ }
+ }
+ return cimServerResVO.getDataBody();
+ }
+
+ public CompletableFuture sendP2P(CompletableFuture future, P2PReqVO p2PReqVO) {
+ return CompletableFuture.runAsync(() -> {
+ try {
+ BaseResponse response = routeApi.p2pRoute(p2PReqVO);
+ if (response.getCode().equals(StatusEnum.OFF_LINE.getCode())) {
+ future.completeExceptionally(new CIMException(StatusEnum.OFF_LINE));
+ }
+ future.complete(null);
+ } catch (Exception e) {
+ future.completeExceptionally(e);
+ event.error("send p2p msg error", e);
+ }
+ });
+ }
+
+ public CompletableFuture sendGroupMsg(ChatReqVO chatReqVO) {
+ return CompletableFuture.runAsync(() -> {
+ try {
+ routeApi.groupRoute(chatReqVO);
+ } catch (Exception e) {
+ event.error("send group msg error", e);
+ }
+ });
+ }
+
+ public void offLine(Long userId) {
+ ChatReqVO vo = new ChatReqVO(userId, "offLine");
+ routeApi.offLine(vo);
+ }
+
+ public Set onlineUser() throws Exception {
+ BaseResponse> onlineUsersResVO = routeApi.onlineUser();
+ return onlineUsersResVO.getDataBody();
+ }
+}
diff --git a/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/impl/ClientBuilderImpl.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/impl/ClientBuilderImpl.java
new file mode 100644
index 00000000..c86c0419
--- /dev/null
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/impl/ClientBuilderImpl.java
@@ -0,0 +1,89 @@
+package com.crossoverjie.cim.client.sdk.impl;
+
+import com.crossoverjie.cim.client.sdk.Client;
+import com.crossoverjie.cim.client.sdk.ClientBuilder;
+import com.crossoverjie.cim.client.sdk.Event;
+import com.crossoverjie.cim.client.sdk.io.MessageListener;
+import com.crossoverjie.cim.client.sdk.io.ReconnectCheck;
+import com.crossoverjie.cim.client.sdk.io.backoff.BackoffStrategy;
+import com.crossoverjie.cim.common.util.StringUtil;
+import java.util.concurrent.ThreadPoolExecutor;
+import okhttp3.OkHttpClient;
+
+public class ClientBuilderImpl implements ClientBuilder {
+
+
+ private final ClientConfigurationData conf;
+
+ public ClientBuilderImpl() {
+ this(new ClientConfigurationData());
+ }
+ public ClientBuilderImpl(ClientConfigurationData conf) {
+ this.conf = conf;
+ }
+
+ @Override
+ public Client build() {
+ return new ClientImpl(conf);
+ }
+
+ @Override
+ public ClientBuilder auth(ClientConfigurationData.Auth auth) {
+ if (auth.getUserId() <= 0 || StringUtil.isEmpty(auth.getUserName())){
+ throw new IllegalArgumentException("userId and userName must be set");
+ }
+ this.conf.setAuth(auth);
+ return this;
+ }
+
+ @Override
+ public ClientBuilder routeUrl(String routeUrl) {
+ if (StringUtil.isEmpty(routeUrl)) {
+ throw new IllegalArgumentException("routeUrl must be set");
+ }
+ this.conf.setRouteUrl(routeUrl);
+ return this;
+ }
+
+ @Override
+ public ClientBuilder loginRetryCount(int loginRetryCount) {
+ this.conf.setLoginRetryCount(loginRetryCount);
+ return this;
+ }
+
+ @Override
+ public ClientBuilder event(Event event) {
+ this.conf.setEvent(event);
+ return this;
+ }
+
+ @Override
+ public ClientBuilder reconnectCheck(ReconnectCheck reconnectCheck) {
+ this.conf.setReconnectCheck(reconnectCheck);
+ return this;
+ }
+
+ @Override
+ public ClientBuilder okHttpClient(OkHttpClient okHttpClient) {
+ this.conf.setOkHttpClient(okHttpClient);
+ return this;
+ }
+
+ @Override
+ public ClientBuilder messageListener(MessageListener messageListener) {
+ this.conf.setMessageListener(messageListener);
+ return this;
+ }
+
+ @Override
+ public ClientBuilder callbackThreadPool(ThreadPoolExecutor callbackThreadPool) {
+ this.conf.setCallbackThreadPool(callbackThreadPool);
+ return this;
+ }
+
+ @Override
+ public ClientBuilder backoffStrategy(BackoffStrategy backoffStrategy) {
+ this.conf.setBackoffStrategy(backoffStrategy);
+ return this;
+ }
+}
diff --git a/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/impl/ClientConfigurationData.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/impl/ClientConfigurationData.java
new file mode 100644
index 00000000..b76883c9
--- /dev/null
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/impl/ClientConfigurationData.java
@@ -0,0 +1,54 @@
+package com.crossoverjie.cim.client.sdk.impl;
+
+import com.crossoverjie.cim.client.sdk.Event;
+import com.crossoverjie.cim.client.sdk.io.backoff.BackoffStrategy;
+import com.crossoverjie.cim.client.sdk.io.MessageListener;
+import com.crossoverjie.cim.client.sdk.io.backoff.RandomBackoff;
+import com.crossoverjie.cim.client.sdk.io.ReconnectCheck;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import java.util.concurrent.ThreadPoolExecutor;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import okhttp3.OkHttpClient;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ClientConfigurationData {
+
+ private Auth auth;
+
+ @Data
+ @AllArgsConstructor
+ @Builder
+ public static class Auth{
+ private long userId;
+ private String userName;
+ }
+
+ private String routeUrl;
+ private int loginRetryCount = 5;
+
+ @JsonIgnore
+ private Event event = new Event.DefaultEvent();
+
+ @JsonIgnore
+ private MessageListener messageListener =
+ (client, properties, msg) -> System.out.printf("id:[%s] msg:[%s]%n \n", client.getAuth(), msg);
+
+ @JsonIgnore
+ private OkHttpClient okHttpClient = new OkHttpClient();
+
+ @JsonIgnore
+ private ThreadPoolExecutor callbackThreadPool;
+
+ @JsonIgnore
+ private ReconnectCheck reconnectCheck = (client) -> true;
+
+ @JsonIgnore
+ private BackoffStrategy backoffStrategy = new RandomBackoff();
+}
diff --git a/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/impl/ClientImpl.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/impl/ClientImpl.java
new file mode 100644
index 00000000..5071f627
--- /dev/null
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/impl/ClientImpl.java
@@ -0,0 +1,256 @@
+package com.crossoverjie.cim.client.sdk.impl;
+
+import static com.crossoverjie.cim.common.enums.StatusEnum.RECONNECT_FAIL;
+import com.crossoverjie.cim.client.sdk.Client;
+import com.crossoverjie.cim.client.sdk.ClientState;
+import com.crossoverjie.cim.client.sdk.ReConnectManager;
+import com.crossoverjie.cim.client.sdk.RouteManager;
+import com.crossoverjie.cim.client.sdk.io.CIMClientHandleInitializer;
+import com.crossoverjie.cim.common.exception.CIMException;
+import com.crossoverjie.cim.common.kit.HeartBeatHandler;
+import com.crossoverjie.cim.common.pojo.CIMUserInfo;
+import com.crossoverjie.cim.common.protocol.BaseCommand;
+import com.crossoverjie.cim.common.protocol.Request;
+import com.crossoverjie.cim.route.api.vo.req.ChatReqVO;
+import com.crossoverjie.cim.route.api.vo.req.LoginReqVO;
+import com.crossoverjie.cim.route.api.vo.req.P2PReqVO;
+import com.crossoverjie.cim.route.api.vo.res.CIMServerResVO;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.util.concurrent.DefaultThreadFactory;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class ClientImpl extends ClientState implements Client {
+
+ @Getter
+ private final ClientConfigurationData conf;
+ private static final int CALLBACK_QUEUE_SIZE = 1024;
+ private static final int CALLBACK_POOL_SIZE = 10;
+
+ // ======= private ========
+ private int errorCount;
+ private SocketChannel channel;
+
+ private final RouteManager routeManager;
+
+ @Getter
+ private final HeartBeatHandler heartBeatHandler = ReConnectManager.createHeartBeatHandler();
+ @Getter
+ private final ReConnectManager reConnectManager = ReConnectManager.createReConnectManager();
+
+ @Getter
+ private static ClientImpl client;
+ @Getter
+ private final Request heartBeatPacket;
+
+ // Client connected server info
+ private CIMServerResVO serverInfo;
+
+ public ClientImpl(ClientConfigurationData conf) {
+ this.conf = conf;
+
+ if (this.conf.getCallbackThreadPool() == null) {
+ BlockingQueue queue = new LinkedBlockingQueue<>(CALLBACK_QUEUE_SIZE);
+ ThreadFactory factory = new ThreadFactoryBuilder()
+ .setNameFormat("msg-callback-%d")
+ .setDaemon(true)
+ .build();
+ this.conf.setCallbackThreadPool(
+ new ThreadPoolExecutor(CALLBACK_POOL_SIZE, CALLBACK_POOL_SIZE, 1, TimeUnit.SECONDS, queue,
+ factory));
+ }
+
+ routeManager = new RouteManager(conf.getRouteUrl(), conf.getOkHttpClient(), conf.getEvent());
+
+ heartBeatPacket = Request.newBuilder()
+ .setRequestId(this.conf.getAuth().getUserId())
+ .setReqMsg("ping")
+ .setCmd(BaseCommand.PING)
+ .build();
+ client = this;
+
+ connectServer(v -> this.conf.getEvent().info("Login success!"));
+ }
+
+ private void connectServer(Consumer success) {
+ doConnectServer().whenComplete((r, e) -> {
+ if (r) {
+ success.accept(null);
+ }
+ if (e != null) {
+ if (e instanceof CIMException cimException && cimException.getErrorCode()
+ .equals(RECONNECT_FAIL.getCode())) {
+ this.conf.getEvent().fatal(this);
+ } else {
+ if (errorCount++ >= this.conf.getLoginRetryCount()) {
+ this.conf.getEvent()
+ .error("The maximum number of reconnections has been reached[{}]times, exit cim client!",
+ errorCount);
+ this.conf.getEvent().fatal(this);
+ }
+ }
+ }
+
+ });
+ }
+
+ /**
+ * 1. User login and get target server
+ * 2. Connect target server
+ * 3. send login cmd to server
+ */
+ private CompletableFuture doConnectServer() {
+ CompletableFuture future = new CompletableFuture<>();
+ this.userLogin(future).ifPresentOrElse((cimServer) -> {
+ this.doConnectServer(cimServer, future);
+ this.loginServer();
+ this.serverInfo = cimServer;
+ future.complete(true);
+ }, () -> {
+ this.conf.getEvent().error("Login fail!, cannot get server info!");
+ this.conf.getEvent().fatal(this);
+ future.complete(false);
+ });
+ return future;
+ }
+
+ /**
+ * Login and get server info
+ *
+ * @return Server info
+ */
+ private Optional userLogin(CompletableFuture future) {
+ LoginReqVO loginReqVO = new LoginReqVO(conf.getAuth().getUserId(),
+ conf.getAuth().getUserName());
+
+ CIMServerResVO cimServer = null;
+ try {
+ cimServer = routeManager.getServer(loginReqVO);
+ log.info("cimServer=[{}]", cimServer);
+ } catch (Exception e) {
+ log.error("login fail", e);
+ future.completeExceptionally(e);
+ }
+ return Optional.ofNullable(cimServer);
+ }
+
+ private final EventLoopGroup group = new NioEventLoopGroup(0, new DefaultThreadFactory("cim-work"));
+
+ private void doConnectServer(CIMServerResVO cimServer, CompletableFuture future) {
+ Bootstrap bootstrap = new Bootstrap();
+ bootstrap.group(group)
+ .channel(NioSocketChannel.class)
+ .handler(new CIMClientHandleInitializer());
+ ChannelFuture sync;
+ try {
+ sync = bootstrap.connect(cimServer.getIp(), cimServer.getCimServerPort()).sync();
+ if (sync.isSuccess()) {
+ this.conf.getEvent().info("Start cim client success!");
+ channel = (SocketChannel) sync.channel();
+ }
+ } catch (InterruptedException e) {
+ future.completeExceptionally(e);
+ }
+ }
+
+ /**
+ * Send login cmd to server
+ */
+ private void loginServer() {
+ Request login = Request.newBuilder()
+ .setRequestId(this.conf.getAuth().getUserId())
+ .setReqMsg(this.conf.getAuth().getUserName())
+ .setCmd(BaseCommand.LOGIN_REQUEST)
+ .build();
+ channel.writeAndFlush(login)
+ .addListener((ChannelFutureListener) channelFuture ->
+ this.conf.getEvent().info("Registry cim server success!")
+ );
+ }
+
+ /**
+ * 1. clear route information.
+ * 2. reconnect.
+ * 3. shutdown reconnect job.
+ * 4. reset reconnect state.
+ * @throws Exception
+ */
+ public void reconnect() throws Exception {
+ if (channel != null && channel.isActive()) {
+ return;
+ }
+ this.serverInfo = null;
+ // clear route information.
+ this.routeManager.offLine(this.getConf().getAuth().getUserId());
+
+ this.conf.getEvent().info("cim trigger reconnecting....");
+
+ this.conf.getBackoffStrategy().runBackoff();
+
+ // don't set State ready, because when connect success, the State will be set to ready automate.
+ connectServer(v -> {
+ this.reConnectManager.reConnectSuccess();
+ this.conf.getEvent().info("Great! reConnect success!!!");
+ });
+ }
+
+ @Override
+ public void close() {
+ if (channel != null) {
+ channel.close();
+ channel = null;
+ }
+ super.setState(ClientState.State.Closed);
+ this.routeManager.offLine(this.getAuth().getUserId());
+ }
+
+ @Override
+ public CompletableFuture sendP2PAsync(P2PReqVO p2PReqVO) {
+ CompletableFuture future = new CompletableFuture<>();
+ p2PReqVO.setUserId(this.conf.getAuth().getUserId());
+ return routeManager.sendP2P(future, p2PReqVO);
+ }
+
+ @Override
+ public CompletableFuture sendGroupAsync(String msg) {
+ // TODO: 2024/9/12 return messageId
+ return this.routeManager.sendGroupMsg(new ChatReqVO(this.conf.getAuth().getUserId(), msg));
+ }
+
+ @Override
+ public ClientConfigurationData.Auth getAuth() {
+ return this.conf.getAuth();
+ }
+
+ @Override
+ public ClientState.State getState() {
+ return super.getState();
+ }
+
+ @Override
+ public Set getOnlineUser() throws Exception {
+ return routeManager.onlineUser();
+ }
+
+ @Override
+ public Optional getServerInfo() {
+ return Optional.ofNullable(this.serverInfo);
+ }
+}
diff --git a/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/CIMClientHandle.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/CIMClientHandle.java
new file mode 100644
index 00000000..f49de355
--- /dev/null
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/CIMClientHandle.java
@@ -0,0 +1,82 @@
+package com.crossoverjie.cim.client.sdk.io;
+
+import com.crossoverjie.cim.client.sdk.ClientState;
+import com.crossoverjie.cim.client.sdk.impl.ClientImpl;
+import com.crossoverjie.cim.common.protocol.BaseCommand;
+import com.crossoverjie.cim.common.protocol.Response;
+import com.crossoverjie.cim.common.util.NettyAttrUtil;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.timeout.IdleState;
+import io.netty.handler.timeout.IdleStateEvent;
+import lombok.extern.slf4j.Slf4j;
+
+@ChannelHandler.Sharable
+@Slf4j
+public class CIMClientHandle extends SimpleChannelInboundHandler {
+
+ @Override
+ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+
+ if (evt instanceof IdleStateEvent idleStateEvent) {
+
+ if (idleStateEvent.state() == IdleState.WRITER_IDLE) {
+
+ ctx.writeAndFlush(ClientImpl.getClient().getHeartBeatPacket()).addListeners((ChannelFutureListener) future -> {
+ if (!future.isSuccess()) {
+ log.error("heart beat error,close Channel");
+ ClientImpl.getClient().getConf().getEvent().warn("heart beat error,close Channel");
+ future.channel().close();
+ }
+ });
+ }
+
+ }
+
+ super.userEventTriggered(ctx, evt);
+ }
+
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) {
+ ClientImpl.getClient().getConf().getEvent().debug("ChannelActive");
+ ClientImpl.getClient().setState(ClientState.State.Ready);
+ }
+
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) {
+
+ if (!ClientImpl.getClient().getConf().getReconnectCheck().isNeedReconnect(ClientImpl.getClient())) {
+ return;
+ }
+ ClientImpl.getClient().setState(ClientState.State.Closed);
+
+ ClientImpl.getClient().getConf().getEvent().warn("Client inactive, let's reconnect");
+ ClientImpl.getClient().getReConnectManager().reConnect(ctx);
+ }
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext ctx, Response msg) {
+
+
+ if (msg.getCmd() == BaseCommand.PING) {
+ ClientImpl.getClient().getConf().getEvent().debug("received ping from server");
+ NettyAttrUtil.updateReaderTime(ctx.channel(), System.currentTimeMillis());
+ }
+
+ if (msg.getCmd() != BaseCommand.PING) {
+ // callback
+ ClientImpl.getClient().getConf().getCallbackThreadPool().execute(() -> {
+ ClientImpl.getClient().getConf().getMessageListener().received(ClientImpl.getClient(), msg.getPropertiesMap(), msg.getResMsg());
+ });
+ }
+
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+ ClientImpl.getClient().getConf().getEvent().error(cause.getCause().toString());
+ ctx.close();
+ }
+}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/init/CIMClientHandleInitializer.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/CIMClientHandleInitializer.java
similarity index 54%
rename from cim-client/src/main/java/com/crossoverjie/cim/client/init/CIMClientHandleInitializer.java
rename to cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/CIMClientHandleInitializer.java
index c68bd67b..fb50e4dc 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/init/CIMClientHandleInitializer.java
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/CIMClientHandleInitializer.java
@@ -1,7 +1,6 @@
-package com.crossoverjie.cim.client.init;
+package com.crossoverjie.cim.client.sdk.io;
-import com.crossoverjie.cim.client.handle.CIMClientHandle;
-import com.crossoverjie.cim.common.protocol.CIMResponseProto;
+import com.crossoverjie.cim.common.protocol.Response;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
@@ -10,32 +9,18 @@
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import io.netty.handler.timeout.IdleStateHandler;
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 23/02/2018 22:47
- * @since JDK 1.8
- */
public class CIMClientHandleInitializer extends ChannelInitializer {
private final CIMClientHandle cimClientHandle = new CIMClientHandle();
@Override
- protected void initChannel(Channel ch) throws Exception {
+ protected void initChannel(Channel ch) {
ch.pipeline()
- //10 秒没发送消息 将IdleStateHandler 添加到 ChannelPipeline 中
.addLast(new IdleStateHandler(0, 10, 0))
- //心跳解码
- //.addLast(new HeartbeatEncode())
-
- // google Protobuf 编解码
- //拆包解码
+ // google Protobuf
.addLast(new ProtobufVarint32FrameDecoder())
- .addLast(new ProtobufDecoder(CIMResponseProto.CIMResProtocol.getDefaultInstance()))
- //
- //拆包编码
+ .addLast(new ProtobufDecoder(Response.getDefaultInstance()))
.addLast(new ProtobufVarint32LengthFieldPrepender())
.addLast(new ProtobufEncoder())
.addLast(cimClientHandle)
diff --git a/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/MessageListener.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/MessageListener.java
new file mode 100644
index 00000000..51375dee
--- /dev/null
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/MessageListener.java
@@ -0,0 +1,14 @@
+package com.crossoverjie.cim.client.sdk.io;
+
+import com.crossoverjie.cim.client.sdk.Client;
+import java.util.Map;
+
+public interface MessageListener {
+
+ /**
+ * @param client client
+ * @param properties meta data
+ * @param msg msgs
+ */
+ void received(Client client, Map properties, String msg);
+}
diff --git a/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/ReconnectCheck.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/ReconnectCheck.java
new file mode 100644
index 00000000..3984cfcb
--- /dev/null
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/ReconnectCheck.java
@@ -0,0 +1,12 @@
+package com.crossoverjie.cim.client.sdk.io;
+
+import com.crossoverjie.cim.client.sdk.Client;
+
+public interface ReconnectCheck {
+
+ /**
+ * By the default, the client will reconnect to the server when the connection is close(inactive).
+ * @return false if the client should not reconnect to the server.
+ */
+ boolean isNeedReconnect(Client client);
+}
diff --git a/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/backoff/BackoffStrategy.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/backoff/BackoffStrategy.java
new file mode 100644
index 00000000..eed72b3a
--- /dev/null
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/backoff/BackoffStrategy.java
@@ -0,0 +1,24 @@
+package com.crossoverjie.cim.client.sdk.io.backoff;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author:qjj
+ * @create: 2024-09-21 12:16
+ * @Description: backoff strategy interface
+ */
+
+public interface BackoffStrategy {
+ /**
+ * @return the backoff time in milliseconds
+ */
+ long nextBackoff();
+
+ /**
+ * Run the backoff strategy
+ * @throws InterruptedException
+ */
+ default void runBackoff() throws InterruptedException {
+ TimeUnit.SECONDS.sleep(nextBackoff());
+ }
+}
diff --git a/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/backoff/RandomBackoff.java b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/backoff/RandomBackoff.java
new file mode 100644
index 00000000..7de4ca5f
--- /dev/null
+++ b/cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/io/backoff/RandomBackoff.java
@@ -0,0 +1,16 @@
+package com.crossoverjie.cim.client.sdk.io.backoff;
+
+/**
+ * @author:qjj
+ * @create: 2024-09-21 12:22
+ * @Description: random backoff strategy
+ */
+
+public class RandomBackoff implements BackoffStrategy {
+
+ @Override
+ public long nextBackoff() {
+ return (int) (Math.random() * 7 + 3);
+ }
+
+}
diff --git a/cim-client-sdk/src/test/java/com/crossoverjie/cim/client/sdk/ClientTest.java b/cim-client-sdk/src/test/java/com/crossoverjie/cim/client/sdk/ClientTest.java
new file mode 100644
index 00000000..e97a9ed9
--- /dev/null
+++ b/cim-client-sdk/src/test/java/com/crossoverjie/cim/client/sdk/ClientTest.java
@@ -0,0 +1,429 @@
+package com.crossoverjie.cim.client.sdk;
+
+import com.crossoverjie.cim.client.sdk.impl.ClientConfigurationData;
+import com.crossoverjie.cim.client.sdk.io.backoff.RandomBackoff;
+import com.crossoverjie.cim.client.sdk.route.AbstractRouteBaseTest;
+import com.crossoverjie.cim.common.constant.Constants;
+import com.crossoverjie.cim.common.pojo.CIMUserInfo;
+import com.crossoverjie.cim.route.api.vo.req.P2PReqVO;
+import com.crossoverjie.cim.route.api.vo.res.CIMServerResVO;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import lombok.Cleanup;
+import lombok.extern.slf4j.Slf4j;
+import org.awaitility.Awaitility;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+@Slf4j
+public class ClientTest extends AbstractRouteBaseTest {
+
+
+ @AfterEach
+ public void tearDown() {
+ super.close();
+ }
+
+ @Test
+ public void groupChat() throws Exception {
+ super.starSingleServer();
+ super.startRoute();
+ String routeUrl = "http://localhost:8083";
+ String cj = "crossoverJie";
+ String zs = "zs";
+ Long id = super.registerAccount(cj);
+ Long zsId = super.registerAccount(zs);
+ var auth1 = ClientConfigurationData.Auth.builder()
+ .userId(id)
+ .userName(cj)
+ .build();
+ var auth2 = ClientConfigurationData.Auth.builder()
+ .userId(zsId)
+ .userName(zs)
+ .build();
+
+ @Cleanup
+ Client client1 = Client.builder()
+ .auth(auth1)
+ .routeUrl(routeUrl)
+ .build();
+ TimeUnit.SECONDS.sleep(3);
+ ClientState.State state = client1.getState();
+ Awaitility.await().atMost(10, TimeUnit.SECONDS)
+ .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, state));
+ Optional serverInfo = client1.getServerInfo();
+ Assertions.assertTrue(serverInfo.isPresent());
+ System.out.println("client1 serverInfo = " + serverInfo.get());
+
+
+ AtomicReference client2Receive = new AtomicReference<>();
+ @Cleanup
+ Client client2 = Client.builder()
+ .auth(auth2)
+ .routeUrl(routeUrl)
+ .messageListener((client, properties, message) -> {
+ client2Receive.set(message);
+ Assertions.assertEquals(properties.get(Constants.MetaKey.USER_ID), String.valueOf(auth1.getUserId()));
+ Assertions.assertEquals(properties.get(Constants.MetaKey.USER_NAME), auth1.getUserName());
+ })
+ .build();
+ TimeUnit.SECONDS.sleep(3);
+ ClientState.State state2 = client2.getState();
+ Awaitility.await().atMost(10, TimeUnit.SECONDS)
+ .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, state2));
+
+ Optional serverInfo2 = client2.getServerInfo();
+ Assertions.assertTrue(serverInfo2.isPresent());
+ System.out.println("client2 serverInfo = " + serverInfo2.get());
+
+ // send msg
+ String msg = "hello";
+ client1.sendGroup(msg);
+
+ Set onlineUser = client1.getOnlineUser();
+ Assertions.assertEquals(onlineUser.size(), 2);
+ onlineUser.forEach(userInfo -> {
+ log.info("online user = {}", userInfo);
+ Long userId = userInfo.getUserId();
+ if (userId.equals(id)) {
+ Assertions.assertEquals(cj, userInfo.getUserName());
+ } else if (userId.equals(zsId)) {
+ Assertions.assertEquals(zs, userInfo.getUserName());
+ }
+ });
+
+ Awaitility.await().untilAsserted(
+ () -> Assertions.assertEquals(msg, client2Receive.get()));
+ super.stopSingle();
+ }
+
+ @Test
+ public void testP2PChat() throws Exception {
+ super.starSingleServer();
+ super.startRoute();
+ String routeUrl = "http://localhost:8083";
+ String cj = "cj";
+ String zs = "zs";
+ String ls = "ls";
+ Long cjId = super.registerAccount(cj);
+ Long zsId = super.registerAccount(zs);
+ Long lsId = super.registerAccount(ls);
+ var auth1 = ClientConfigurationData.Auth.builder()
+ .userName(cj)
+ .userId(cjId)
+ .build();
+ var auth2 = ClientConfigurationData.Auth.builder()
+ .userName(zs)
+ .userId(zsId)
+ .build();
+ var auth3 = ClientConfigurationData.Auth.builder()
+ .userName(ls)
+ .userId(lsId)
+ .build();
+
+ @Cleanup
+ Client client1 = Client.builder()
+ .auth(auth1)
+ .routeUrl(routeUrl)
+ .build();
+ TimeUnit.SECONDS.sleep(3);
+ ClientState.State state = client1.getState();
+ Awaitility.await().atMost(10, TimeUnit.SECONDS)
+ .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, state));
+ Optional serverInfo = client1.getServerInfo();
+ Assertions.assertTrue(serverInfo.isPresent());
+ System.out.println("client1 serverInfo = " + serverInfo.get());
+
+
+ // client2
+ AtomicReference client2Receive = new AtomicReference<>();
+ @Cleanup
+ Client client2 = Client.builder()
+ .auth(auth2)
+ .routeUrl(routeUrl)
+ .messageListener((client, properties, message) -> client2Receive.set(message))
+ .build();
+ TimeUnit.SECONDS.sleep(3);
+ ClientState.State state2 = client2.getState();
+ Awaitility.await().atMost(10, TimeUnit.SECONDS)
+ .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, state2));
+
+ Optional serverInfo2 = client2.getServerInfo();
+ Assertions.assertTrue(serverInfo2.isPresent());
+ System.out.println("client2 serverInfo = " + serverInfo2.get());
+
+ // client3
+ AtomicReference client3Receive = new AtomicReference<>();
+ @Cleanup
+ Client client3 = Client.builder()
+ .auth(auth3)
+ .routeUrl(routeUrl)
+ .messageListener((client, properties, message) -> {
+ log.info("client3 receive message = {}", message);
+ client3Receive.set(message);
+ })
+ .build();
+ TimeUnit.SECONDS.sleep(3);
+ ClientState.State state3 = client3.getState();
+ Awaitility.await().atMost(10, TimeUnit.SECONDS)
+ .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, state3));
+
+ Optional serverInfo3 = client3.getServerInfo();
+ Assertions.assertTrue(serverInfo3.isPresent());
+ System.out.println("client3 serverInfo = " + serverInfo3.get());
+
+ // send msg to client3
+ String msg = "hello";
+ client1.sendP2P(P2PReqVO.builder()
+ .receiveUserId(lsId)
+ .msg(msg)
+ .build());
+
+ Set onlineUser = client1.getOnlineUser();
+ Assertions.assertEquals(onlineUser.size(), 3);
+ onlineUser.forEach(userInfo -> {
+ log.info("online user = {}", userInfo);
+ Long userId = userInfo.getUserId();
+ if (userId.equals(cjId)) {
+ Assertions.assertEquals(cj, userInfo.getUserName());
+ } else if (userId.equals(zsId)) {
+ Assertions.assertEquals(zs, userInfo.getUserName());
+ } else if (userId.equals(lsId)) {
+ Assertions.assertEquals(ls, userInfo.getUserName());
+ }
+ });
+
+ Awaitility.await().untilAsserted(
+ () -> Assertions.assertEquals(msg, client3Receive.get()));
+ Awaitility.await().untilAsserted(
+ () -> Assertions.assertNull(client2Receive.get()));
+ super.stopSingle();
+ }
+
+ /**
+ * 1. Start two servers.
+ * 2. Start two client, and send message.
+ * 3. Stop one server which is connected by client1.
+ * 4. Wait for client1 reconnect.
+ * 5. Send message again.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testReconnect() throws Exception {
+ super.startTwoServer();
+ super.startRoute();
+
+ String routeUrl = "http://localhost:8083";
+ String cj = "cj";
+ String zs = "zs";
+ Long cjId = super.registerAccount(cj);
+ Long zsId = super.registerAccount(zs);
+ var auth1 = ClientConfigurationData.Auth.builder()
+ .userName(cj)
+ .userId(cjId)
+ .build();
+ var auth2 = ClientConfigurationData.Auth.builder()
+ .userName(zs)
+ .userId(zsId)
+ .build();
+ var backoffStrategy = new RandomBackoff();
+
+ @Cleanup
+ Client client1 = Client.builder()
+ .auth(auth1)
+ .routeUrl(routeUrl)
+ .backoffStrategy(backoffStrategy)
+ .build();
+ TimeUnit.SECONDS.sleep(3);
+ ClientState.State state = client1.getState();
+ Awaitility.await().atMost(10, TimeUnit.SECONDS)
+ .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, state));
+
+
+ AtomicReference client2Receive = new AtomicReference<>();
+ @Cleanup
+ Client client2 = Client.builder()
+ .auth(auth2)
+ .routeUrl(routeUrl)
+ .messageListener((client, properties, message) -> client2Receive.set(message))
+ .backoffStrategy(backoffStrategy)
+ .build();
+ TimeUnit.SECONDS.sleep(3);
+ ClientState.State state2 = client2.getState();
+ Awaitility.await().atMost(10, TimeUnit.SECONDS)
+ .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, state2));
+
+ Optional serverInfo2 = client2.getServerInfo();
+ Assertions.assertTrue(serverInfo2.isPresent());
+ System.out.println("client2 serverInfo = " + serverInfo2.get());
+
+ // send msg
+ String msg = "hello";
+ client1.sendGroup(msg);
+ Awaitility.await()
+ .untilAsserted(() -> Assertions.assertEquals(msg, client2Receive.get()));
+ client2Receive.set("");
+
+
+ System.out.println("ready to restart server");
+ TimeUnit.SECONDS.sleep(3);
+ Optional serverInfo = client1.getServerInfo();
+ Assertions.assertTrue(serverInfo.isPresent());
+ System.out.println("server info = " + serverInfo.get());
+
+ super.stopServer(serverInfo.get().getCimServerPort());
+ System.out.println("stop server success! " + serverInfo.get());
+
+
+ // Waiting server stopped, and client reconnect.
+ TimeUnit.SECONDS.sleep(30);
+ System.out.println("reconnect state: " + client1.getState());
+ Awaitility.await().atMost(15, TimeUnit.SECONDS)
+ .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, state));
+ serverInfo = client1.getServerInfo();
+ Assertions.assertTrue(serverInfo.isPresent());
+ System.out.println("client1 reconnect server info = " + serverInfo.get());
+
+ // Send message again.
+ log.info("send message again, client2Receive = {}", client2Receive.get());
+ client1.sendGroup(msg);
+ Awaitility.await()
+ .untilAsserted(() -> Assertions.assertEquals(msg, client2Receive.get()));
+ super.stopTwoServer();
+ }
+
+ @Test
+ public void offLineAndOnline() throws Exception {
+ super.starSingleServer();
+ super.startRoute();
+ String routeUrl = "http://localhost:8083";
+ String cj = "crossoverJie";
+ String zs = "zs";
+ Long id = super.registerAccount(cj);
+ Long zsId = super.registerAccount(zs);
+ var auth1 = ClientConfigurationData.Auth.builder()
+ .userId(id)
+ .userName(cj)
+ .build();
+ var auth2 = ClientConfigurationData.Auth.builder()
+ .userId(zsId)
+ .userName(zs)
+ .build();
+
+ @Cleanup
+ Client client1 = Client.builder()
+ .auth(auth1)
+ .routeUrl(routeUrl)
+ .build();
+ TimeUnit.SECONDS.sleep(3);
+ ClientState.State state = client1.getState();
+ Awaitility.await().atMost(10, TimeUnit.SECONDS)
+ .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, state));
+ Optional serverInfo = client1.getServerInfo();
+ Assertions.assertTrue(serverInfo.isPresent());
+ System.out.println("client1 serverInfo = " + serverInfo.get());
+
+
+ AtomicReference client2Receive = new AtomicReference<>();
+ Client client2 = Client.builder()
+ .auth(auth2)
+ .routeUrl(routeUrl)
+ .messageListener((client, properties, message) -> client2Receive.set(message))
+ // Avoid auto reconnect, this test will manually close client.
+ .reconnectCheck((client) -> false)
+ .build();
+ TimeUnit.SECONDS.sleep(3);
+ ClientState.State state2 = client2.getState();
+ Awaitility.await().atMost(10, TimeUnit.SECONDS)
+ .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, state2));
+
+ Optional serverInfo2 = client2.getServerInfo();
+ Assertions.assertTrue(serverInfo2.isPresent());
+ System.out.println("client2 serverInfo = " + serverInfo2.get());
+
+ // send msg
+ String msg = "hello";
+ client1.sendGroup(msg);
+ Awaitility.await().untilAsserted(
+ () -> Assertions.assertEquals(msg, client2Receive.get()));
+ client2Receive.set("");
+
+ // Manually offline
+ client2.close();
+ TimeUnit.SECONDS.sleep(10);
+ client2 = Client.builder()
+ .auth(auth2)
+ .routeUrl(routeUrl)
+ .messageListener((client, properties, message) -> client2Receive.set(message))
+ // Avoid to auto reconnect, this test will manually close client.
+ .reconnectCheck((client) -> false)
+ .build();
+ ClientState.State state3 = client2.getState();
+ Awaitility.await().atMost(10, TimeUnit.SECONDS)
+ .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, state3));
+
+ // send msg again
+ client1.sendGroup(msg);
+ Awaitility.await().untilAsserted(
+ () -> Assertions.assertEquals(msg, client2Receive.get()));
+
+ super.stopSingle();
+ }
+
+ @Test
+ public void testClose() throws Exception {
+ super.starSingleServer();
+ super.startRoute();
+ String routeUrl = "http://localhost:8083";
+ String cj = "crossoverJie";
+ Long id = super.registerAccount(cj);
+ var auth1 = ClientConfigurationData.Auth.builder()
+ .userId(id)
+ .userName(cj)
+ .build();
+
+ Client client1 = Client.builder()
+ .auth(auth1)
+ .routeUrl(routeUrl)
+ .build();
+ TimeUnit.SECONDS.sleep(3);
+ ClientState.State state = client1.getState();
+ Awaitility.await().atMost(10, TimeUnit.SECONDS)
+ .untilAsserted(() -> Assertions.assertEquals(ClientState.State.Ready, state));
+ Optional serverInfo = client1.getServerInfo();
+ Assertions.assertTrue(serverInfo.isPresent());
+ System.out.println("client1 serverInfo = " + serverInfo.get());
+
+ client1.close();
+ ClientState.State state1 = client1.getState();
+ Assertions.assertEquals(ClientState.State.Closed, state1);
+ super.stopSingle();
+ }
+
+ @Test
+ public void testIncorrectUser() throws Exception {
+ super.starSingleServer();
+ super.startRoute();
+ String routeUrl = "http://localhost:8083";
+ String cj = "xx";
+ long id = 100L;
+ var auth1 = ClientConfigurationData.Auth.builder()
+ .userId(id)
+ .userName(cj)
+ .build();
+
+ Client client1 = Client.builder()
+ .auth(auth1)
+ .routeUrl(routeUrl)
+ .build();
+ TimeUnit.SECONDS.sleep(3);
+
+ Assertions.assertDoesNotThrow(client1::close);
+
+ super.stopSingle();
+ }
+}
\ No newline at end of file
diff --git a/cim-client-sdk/src/test/resources/application-route.yaml b/cim-client-sdk/src/test/resources/application-route.yaml
new file mode 100644
index 00000000..305a9aa1
--- /dev/null
+++ b/cim-client-sdk/src/test/resources/application-route.yaml
@@ -0,0 +1,49 @@
+spring:
+ application:
+ name:
+ cim-forward-route
+ data:
+ redis:
+ host: 127.0.0.1
+ port: 6379
+ jedis:
+ pool:
+ max-active: 100
+ max-idle: 100
+ max-wait: 1000
+ min-idle: 10
+# web port
+server:
+ port: 8083
+
+logging:
+ level:
+ root: info
+
+ # enable swagger
+springdoc:
+ swagger-ui:
+ enabled: true
+
+app:
+ zk:
+ connect:
+ timeout: 30000
+ root: /route
+
+ # route strategy
+ #app.route.way=com.crossoverjie.cim.common.route.algorithm.loop.LoopHandle
+
+ # route strategy
+ #app.route.way=com.crossoverjie.cim.common.route.algorithm.random.RandomHandle
+
+ # route strategy
+ route:
+ way:
+ handler: com.crossoverjie.cim.common.route.algorithm.loop.LoopHandle
+
+ #app.route.way.consitenthash=com.crossoverjie.cim.common.route.algorithm.consistenthash.SortArrayMapConsistentHash
+
+ consitenthash: com.crossoverjie.cim.common.route.algorithm.consistenthash.TreeMapConsistentHash
+
+
diff --git a/cim-client/pom.xml b/cim-client/pom.xml
index 47d7d931..9e628ddb 100644
--- a/cim-client/pom.xml
+++ b/cim-client/pom.xml
@@ -32,6 +32,11 @@
cim-common
+
+ com.crossoverjie.netty
+ cim-client-sdk
+
+
org.springframework.boot
spring-boot-starter-web
@@ -42,6 +47,12 @@
test
+
+ org.junit.vintage
+ junit-vintage-engine
+ test
+
+
org.springframework.boot
spring-boot-configuration-processor
@@ -99,4 +110,5 @@
+
\ No newline at end of file
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/CIMClientApplication.java b/cim-client/src/main/java/com/crossoverjie/cim/client/CIMClientApplication.java
index 8c81cdb4..092b95ca 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/CIMClientApplication.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/CIMClientApplication.java
@@ -1,9 +1,7 @@
package com.crossoverjie.cim.client;
import com.crossoverjie.cim.client.scanner.Scan;
-import com.crossoverjie.cim.client.service.impl.ClientInfo;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -15,19 +13,17 @@
@SpringBootApplication
public class CIMClientApplication implements CommandLineRunner{
- @Autowired
- private ClientInfo clientInfo ;
+
public static void main(String[] args) {
SpringApplication.run(CIMClientApplication.class, args);
- log.info("启动 Client 服务成功");
+ log.info("Client start success");
}
@Override
- public void run(String... args) throws Exception {
+ public void run(String... args) {
Scan scan = new Scan() ;
Thread thread = new Thread(scan);
thread.setName("scan-thread");
thread.start();
- clientInfo.saveStartDate();
}
}
\ No newline at end of file
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/client/CIMClient.java b/cim-client/src/main/java/com/crossoverjie/cim/client/client/CIMClient.java
deleted file mode 100644
index e0dbe90d..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/client/CIMClient.java
+++ /dev/null
@@ -1,232 +0,0 @@
-package com.crossoverjie.cim.client.client;
-
-import com.crossoverjie.cim.client.config.AppConfiguration;
-import com.crossoverjie.cim.client.init.CIMClientHandleInitializer;
-import com.crossoverjie.cim.client.service.EchoService;
-import com.crossoverjie.cim.client.service.ReConnectManager;
-import com.crossoverjie.cim.client.service.RouteRequest;
-import com.crossoverjie.cim.client.service.impl.ClientInfo;
-import com.crossoverjie.cim.client.thread.ContextHolder;
-import com.crossoverjie.cim.client.vo.req.GoogleProtocolVO;
-import com.crossoverjie.cim.client.vo.req.LoginReqVO;
-import com.crossoverjie.cim.client.vo.res.CIMServerResVO;
-import com.crossoverjie.cim.common.constant.Constants;
-import com.crossoverjie.cim.common.protocol.CIMRequestProto;
-import io.netty.bootstrap.Bootstrap;
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelFutureListener;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.channel.socket.SocketChannel;
-import io.netty.channel.socket.nio.NioSocketChannel;
-import io.netty.util.concurrent.DefaultThreadFactory;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-
-import jakarta.annotation.PostConstruct;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 22/05/2018 14:19
- * @since JDK 1.8
- */
-@Component
-@Slf4j
-public class CIMClient {
-
-
- private EventLoopGroup group = new NioEventLoopGroup(0, new DefaultThreadFactory("cim-work"));
-
- @Value("${cim.user.id}")
- private long userId;
-
- @Value("${cim.user.userName}")
- private String userName;
-
- private SocketChannel channel;
-
- @Autowired
- private EchoService echoService ;
-
- @Autowired
- private RouteRequest routeRequest;
-
- @Autowired
- private AppConfiguration configuration;
-
-
- @Autowired
- private ClientInfo clientInfo;
-
- @Autowired
- private ReConnectManager reConnectManager ;
-
- /**
- * 重试次数
- */
- private int errorCount;
-
- @PostConstruct
- public void start() throws Exception {
-
- //登录 + 获取可以使用的服务器 ip+port
- CIMServerResVO.ServerInfo cimServer = userLogin();
-
- //启动客户端
- startClient(cimServer);
-
- //向服务端注册
- loginCIMServer();
-
-
- }
-
- /**
- * 启动客户端
- *
- * @param cimServer
- * @throws Exception
- */
- private void startClient(CIMServerResVO.ServerInfo cimServer) {
- Bootstrap bootstrap = new Bootstrap();
- bootstrap.group(group)
- .channel(NioSocketChannel.class)
- .handler(new CIMClientHandleInitializer())
- ;
-
- ChannelFuture future = null;
- try {
- future = bootstrap.connect(cimServer.getIp(), cimServer.getCimServerPort()).sync();
- } catch (Exception e) {
- errorCount++;
-
- if (errorCount >= configuration.getErrorCount()) {
- log.error("连接失败次数达到上限[{}]次", errorCount);
-// shutdownService.closeMsgHandle();
- }
- log.error("Connect fail!", e);
- }
- if (future.isSuccess()) {
- echoService.echo("Start cim client success!");
- log.info("启动 cim client 成功");
- }
- channel = (SocketChannel) future.channel();
- }
-
- /**
- * 登录+路由服务器
- *
- * @return 路由服务器信息
- * @throws Exception
- */
- private CIMServerResVO.ServerInfo userLogin() {
- LoginReqVO loginReqVO = new LoginReqVO(userId, userName);
- CIMServerResVO.ServerInfo cimServer = null;
- try {
- cimServer = routeRequest.getCIMServer(loginReqVO);
-
- //保存系统信息
- clientInfo.saveServiceInfo(cimServer.getIp() + ":" + cimServer.getCimServerPort())
- .saveUserInfo(userId, userName);
-
- log.info("cimServer=[{}]", cimServer.toString());
- } catch (Exception e) {
- errorCount++;
-
- if (errorCount >= configuration.getErrorCount()) {
- echoService.echo("The maximum number of reconnections has been reached[{}]times, close cim client!", errorCount);
-// shutdownService.closeMsgHandle();
- }
- log.error("login fail", e);
- }
- return cimServer;
- }
-
- /**
- * 向服务器注册
- */
- private void loginCIMServer() {
- CIMRequestProto.CIMReqProtocol login = CIMRequestProto.CIMReqProtocol.newBuilder()
- .setRequestId(userId)
- .setReqMsg(userName)
- .setType(Constants.CommandType.LOGIN)
- .build();
- ChannelFuture future = channel.writeAndFlush(login);
- future.addListener((ChannelFutureListener) channelFuture ->
- echoService.echo("Registry cim server success!")
- );
- }
-
- /**
- * 发送消息字符串
- *
- * @param msg
- */
- public void sendStringMsg(String msg) {
- ByteBuf message = Unpooled.buffer(msg.getBytes().length);
- message.writeBytes(msg.getBytes());
- ChannelFuture future = channel.writeAndFlush(message);
- future.addListener((ChannelFutureListener) channelFuture ->
- log.info("客户端手动发消息成功={}", msg));
-
- }
-
- /**
- * 发送 Google Protocol 编解码字符串
- *
- * @param googleProtocolVO
- */
- public void sendGoogleProtocolMsg(GoogleProtocolVO googleProtocolVO) {
-
- CIMRequestProto.CIMReqProtocol protocol = CIMRequestProto.CIMReqProtocol.newBuilder()
- .setRequestId(googleProtocolVO.getRequestId())
- .setReqMsg(googleProtocolVO.getMsg())
- .setType(Constants.CommandType.MSG)
- .build();
-
-
- ChannelFuture future = channel.writeAndFlush(protocol);
- future.addListener((ChannelFutureListener) channelFuture ->
- log.info("客户端手动发送 Google Protocol 成功={}", googleProtocolVO.toString()));
-
- }
-
-
- /**
- * 1. clear route information.
- * 2. reconnect.
- * 3. shutdown reconnect job.
- * 4. reset reconnect state.
- * @throws Exception
- */
- public void reconnect() throws Exception {
- if (channel != null && channel.isActive()) {
- return;
- }
- //首先清除路由信息,下线
- routeRequest.offLine();
-
- echoService.echo("cim server shutdown, reconnecting....");
- start();
- echoService.echo("Great! reConnect success!!!");
- reConnectManager.reConnectSuccess();
- ContextHolder.clear();
- }
-
- /**
- * 关闭
- *
- * @throws InterruptedException
- */
- public void close() throws InterruptedException {
- if (channel != null){
- channel.close();
- }
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/config/AppConfiguration.java b/cim-client/src/main/java/com/crossoverjie/cim/client/config/AppConfiguration.java
index 9bc86e49..a0ffad31 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/config/AppConfiguration.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/config/AppConfiguration.java
@@ -1,5 +1,6 @@
package com.crossoverjie.cim.client.config;
+import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@@ -11,6 +12,7 @@
* @since JDK 1.8
*/
@Component
+@Data
public class AppConfiguration {
@Value("${cim.user.id}")
@@ -22,54 +24,16 @@ public class AppConfiguration {
@Value("${cim.msg.logger.path}")
private String msgLoggerPath ;
-
@Value("${cim.heartbeat.time}")
private long heartBeatTime ;
@Value("${cim.reconnect.count}")
- private int errorCount ;
-
- public Long getUserId() {
- return userId;
- }
-
- public void setUserId(Long userId) {
- this.userId = userId;
- }
-
- public String getUserName() {
- return userName;
- }
-
- public void setUserName(String userName) {
- this.userName = userName;
- }
-
- public String getMsgLoggerPath() {
- return msgLoggerPath;
- }
-
- public void setMsgLoggerPath(String msgLoggerPath) {
- this.msgLoggerPath = msgLoggerPath;
- }
-
-
- public long getHeartBeatTime() {
- return heartBeatTime;
- }
-
- public void setHeartBeatTime(long heartBeatTime) {
- this.heartBeatTime = heartBeatTime;
- }
-
-
-
-
- public int getErrorCount() {
- return errorCount;
- }
-
- public void setErrorCount(int errorCount) {
- this.errorCount = errorCount;
- }
+ private int reconnectCount;
+
+ @Value("${cim.route.url}")
+ private String routeUrl;
+ @Value("${cim.callback.thread.queue.size}")
+ private int queueSize;
+ @Value("${cim.callback.thread.pool.size}")
+ private int poolSize;
}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/config/BeanConfig.java b/cim-client/src/main/java/com/crossoverjie/cim/client/config/BeanConfig.java
index ef1d488b..30ea454f 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/config/BeanConfig.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/config/BeanConfig.java
@@ -1,110 +1,108 @@
package com.crossoverjie.cim.client.config;
-import com.crossoverjie.cim.client.handle.MsgHandleCaller;
+import com.crossoverjie.cim.client.sdk.Client;
+import com.crossoverjie.cim.client.sdk.Event;
+import com.crossoverjie.cim.client.sdk.impl.ClientConfigurationData;
+import com.crossoverjie.cim.client.sdk.io.backoff.RandomBackoff;
+import com.crossoverjie.cim.client.service.MsgLogger;
+import com.crossoverjie.cim.client.service.ShutDownSign;
import com.crossoverjie.cim.client.service.impl.MsgCallBackListener;
-import com.crossoverjie.cim.common.constant.Constants;
import com.crossoverjie.cim.common.data.construct.RingBufferWheel;
-import com.crossoverjie.cim.common.protocol.CIMRequestProto;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import jakarta.annotation.Resource;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
-import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import java.util.concurrent.*;
-
/**
* Function:bean 配置
*
* @author crossoverJie
- * Date: 24/05/2018 15:55
+ * Date: 24/05/2018 15:55
* @since JDK 1.8
*/
@Configuration
public class BeanConfig {
- @Value("${cim.user.id}")
- private long userId;
+ @Resource
+ private AppConfiguration appConfiguration;
- @Value("${cim.callback.thread.queue.size}")
- private int queueSize;
+ @Resource
+ private ShutDownSign shutDownSign;
- @Value("${cim.callback.thread.pool.size}")
- private int poolSize;
+ @Resource
+ private MsgLogger msgLogger;
- /**
- * 创建心跳单例
- * @return
- */
- @Bean(value = "heartBeat")
- public CIMRequestProto.CIMReqProtocol heartBeat() {
- CIMRequestProto.CIMReqProtocol heart = CIMRequestProto.CIMReqProtocol.newBuilder()
- .setRequestId(userId)
- .setReqMsg("ping")
- .setType(Constants.CommandType.PING)
+ @Bean
+ public Client buildClient(@Qualifier("callBackThreadPool") ThreadPoolExecutor callbackThreadPool,
+ Event event) {
+ OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(3, TimeUnit.SECONDS)
+ .readTimeout(3, TimeUnit.SECONDS)
+ .writeTimeout(3, TimeUnit.SECONDS)
+ .retryOnConnectionFailure(true).build();
+
+ return Client.builder()
+ .auth(ClientConfigurationData.Auth.builder()
+ .userName(appConfiguration.getUserName())
+ .userId(appConfiguration.getUserId())
+ .build())
+ .routeUrl(appConfiguration.getRouteUrl())
+ .loginRetryCount(appConfiguration.getReconnectCount())
+ .event(event)
+ .reconnectCheck(client -> !shutDownSign.checkStatus())
+ .okHttpClient(okHttpClient)
+ .messageListener(new MsgCallBackListener(msgLogger, event))
+ .callbackThreadPool(callbackThreadPool)
+ .backoffStrategy(new RandomBackoff())
.build();
- return heart;
}
-
/**
* http client
+ *
* @return okHttp
*/
@Bean
public OkHttpClient okHttpClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
- builder.connectTimeout(30, TimeUnit.SECONDS)
- .readTimeout(10, TimeUnit.SECONDS)
- .writeTimeout(10,TimeUnit.SECONDS)
+ builder.connectTimeout(3, TimeUnit.SECONDS)
+ .readTimeout(3, TimeUnit.SECONDS)
+ .writeTimeout(3, TimeUnit.SECONDS)
.retryOnConnectionFailure(true);
return builder.build();
}
/**
- * 创建回调线程池
+ * Create callback thread pool
+ *
* @return
*/
@Bean("callBackThreadPool")
- public ThreadPoolExecutor buildCallerThread(){
- BlockingQueue queue = new LinkedBlockingQueue(queueSize);
- ThreadFactory product = new ThreadFactoryBuilder()
+ public ThreadPoolExecutor buildCallerThread() {
+ BlockingQueue queue = new LinkedBlockingQueue<>(appConfiguration.getQueueSize());
+ ThreadFactory executor = new ThreadFactoryBuilder()
.setNameFormat("msg-callback-%d")
.setDaemon(true)
.build();
- ThreadPoolExecutor productExecutor = new ThreadPoolExecutor(poolSize, poolSize, 1, TimeUnit.MILLISECONDS, queue,product);
- return productExecutor ;
- }
-
-
- @Bean("scheduledTask")
- public ScheduledExecutorService buildSchedule(){
- ThreadFactory sche = new ThreadFactoryBuilder()
- .setNameFormat("reConnect-job-%d")
- .setDaemon(true)
- .build();
- ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1,sche) ;
- return scheduledExecutorService ;
- }
-
- /**
- * 回调 bean
- * @return
- */
- @Bean
- public MsgHandleCaller buildCaller(){
- MsgHandleCaller caller = new MsgHandleCaller(new MsgCallBackListener()) ;
-
- return caller ;
+ return new ThreadPoolExecutor(appConfiguration.getPoolSize(), appConfiguration.getPoolSize(), 1,
+ TimeUnit.MILLISECONDS, queue, executor);
}
@Bean
- public RingBufferWheel bufferWheel(){
- ExecutorService executorService = Executors.newFixedThreadPool(2) ;
- return new RingBufferWheel(executorService) ;
+ public RingBufferWheel bufferWheel() {
+ ExecutorService executorService = Executors.newFixedThreadPool(2);
+ return new RingBufferWheel(executorService);
}
}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/constant/Emoji.java b/cim-client/src/main/java/com/crossoverjie/cim/client/constant/Emoji.java
deleted file mode 100644
index cc7c9f57..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/constant/Emoji.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.crossoverjie.cim.client.constant;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2019-08-24 22:53
- * @since JDK 1.8
- */
-public class Emoji {
-
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/controller/IndexController.java b/cim-client/src/main/java/com/crossoverjie/cim/client/controller/IndexController.java
deleted file mode 100644
index a1c8c2fb..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/controller/IndexController.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.crossoverjie.cim.client.controller;
-
-import com.crossoverjie.cim.client.client.CIMClient;
-import com.crossoverjie.cim.client.service.RouteRequest;
-import com.crossoverjie.cim.client.vo.req.GoogleProtocolVO;
-import com.crossoverjie.cim.client.vo.req.GroupReqVO;
-import com.crossoverjie.cim.client.vo.req.SendMsgReqVO;
-import com.crossoverjie.cim.client.vo.req.StringReqVO;
-import com.crossoverjie.cim.client.vo.res.SendMsgResVO;
-import com.crossoverjie.cim.common.enums.StatusEnum;
-import com.crossoverjie.cim.common.res.BaseResponse;
-import com.crossoverjie.cim.common.res.NULLBody;
-import io.swagger.v3.oas.annotations.Operation;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 22/05/2018 14:46
- * @since JDK 1.8
- */
-@Controller
-@RequestMapping("/")
-public class IndexController {
-
-
- @Autowired
- private CIMClient heartbeatClient ;
-
-
-
- @Autowired
- private RouteRequest routeRequest ;
-
-
- /**
- * 向服务端发消息 字符串
- * @param stringReqVO
- * @return
- */
- @Operation(summary = "客户端发送消息,字符串")
- @RequestMapping(value = "sendStringMsg", method = RequestMethod.POST)
- @ResponseBody
- public BaseResponse sendStringMsg(@RequestBody StringReqVO stringReqVO){
- BaseResponse res = new BaseResponse();
-
- for (int i = 0; i < 100; i++) {
- heartbeatClient.sendStringMsg(stringReqVO.getMsg()) ;
- }
-
- // TODO: 2024/5/30 metrics
-
- SendMsgResVO sendMsgResVO = new SendMsgResVO() ;
- sendMsgResVO.setMsg("OK") ;
- res.setCode(StatusEnum.SUCCESS.getCode()) ;
- res.setMessage(StatusEnum.SUCCESS.getMessage()) ;
- return res ;
- }
-
- /**
- * 向服务端发消息 Google ProtoBuf
- * @param googleProtocolVO
- * @return
- */
- @Operation(summary = "向服务端发消息 Google ProtoBuf")
- @RequestMapping(value = "sendProtoBufMsg", method = RequestMethod.POST)
- @ResponseBody
- public BaseResponse sendProtoBufMsg(@RequestBody GoogleProtocolVO googleProtocolVO){
- BaseResponse res = new BaseResponse();
-
- for (int i = 0; i < 100; i++) {
- heartbeatClient.sendGoogleProtocolMsg(googleProtocolVO) ;
- }
-
- // TODO: 2024/5/30 metrics
-
- SendMsgResVO sendMsgResVO = new SendMsgResVO() ;
- sendMsgResVO.setMsg("OK") ;
- res.setCode(StatusEnum.SUCCESS.getCode()) ;
- res.setMessage(StatusEnum.SUCCESS.getMessage()) ;
- return res ;
- }
-
-
-
- /**
- * 群发消息
- * @param sendMsgReqVO
- * @return
- */
- @Operation(summary = "群发消息")
- @RequestMapping(value = "sendGroupMsg",method = RequestMethod.POST)
- @ResponseBody
- public BaseResponse sendGroupMsg(@RequestBody SendMsgReqVO sendMsgReqVO) throws Exception {
- BaseResponse res = new BaseResponse();
-
- GroupReqVO groupReqVO = new GroupReqVO(sendMsgReqVO.getUserId(),sendMsgReqVO.getMsg()) ;
- routeRequest.sendGroupMsg(groupReqVO) ;
-
- // TODO: 2024/5/30 metrics
-
- res.setCode(StatusEnum.SUCCESS.getCode()) ;
- res.setMessage(StatusEnum.SUCCESS.getMessage()) ;
- return res ;
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/handle/CIMClientHandle.java b/cim-client/src/main/java/com/crossoverjie/cim/client/handle/CIMClientHandle.java
deleted file mode 100644
index 791fd019..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/handle/CIMClientHandle.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package com.crossoverjie.cim.client.handle;
-
-import com.crossoverjie.cim.client.service.EchoService;
-import com.crossoverjie.cim.client.service.ReConnectManager;
-import com.crossoverjie.cim.client.service.ShutDownMsg;
-import com.crossoverjie.cim.client.service.impl.EchoServiceImpl;
-import com.crossoverjie.cim.client.util.SpringBeanFactory;
-import com.crossoverjie.cim.common.constant.Constants;
-import com.crossoverjie.cim.common.protocol.CIMRequestProto;
-import com.crossoverjie.cim.common.protocol.CIMResponseProto;
-import com.crossoverjie.cim.common.util.NettyAttrUtil;
-import com.vdurmont.emoji.EmojiParser;
-import io.netty.channel.ChannelFutureListener;
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.SimpleChannelInboundHandler;
-import io.netty.handler.timeout.IdleState;
-import io.netty.handler.timeout.IdleStateEvent;
-import lombok.extern.slf4j.Slf4j;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ThreadPoolExecutor;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 16/02/2018 18:09
- * @since JDK 1.8
- */
-@ChannelHandler.Sharable
-@Slf4j
-public class CIMClientHandle extends SimpleChannelInboundHandler {
-
-
- private MsgHandleCaller caller;
-
- private ThreadPoolExecutor threadPoolExecutor;
-
- private ScheduledExecutorService scheduledExecutorService;
-
- private ReConnectManager reConnectManager;
-
- private ShutDownMsg shutDownMsg;
-
- private EchoService echoService;
-
-
- @Override
- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
-
- if (evt instanceof IdleStateEvent) {
- IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
-
- if (idleStateEvent.state() == IdleState.WRITER_IDLE) {
- CIMRequestProto.CIMReqProtocol heartBeat = SpringBeanFactory.getBean("heartBeat",
- CIMRequestProto.CIMReqProtocol.class);
- ctx.writeAndFlush(heartBeat).addListeners((ChannelFutureListener) future -> {
- if (!future.isSuccess()) {
- log.error("IO error,close Channel");
- future.channel().close();
- }
- });
- }
-
- }
-
- super.userEventTriggered(ctx, evt);
- }
-
- @Override
- public void channelActive(ChannelHandlerContext ctx) throws Exception {
- //客户端和服务端建立连接时调用
- log.info("cim server connect success!");
- }
-
- @Override
- public void channelInactive(ChannelHandlerContext ctx) throws Exception {
-
- if (shutDownMsg == null) {
- shutDownMsg = SpringBeanFactory.getBean(ShutDownMsg.class);
- }
-
- //用户主动退出,不执行重连逻辑
- if (shutDownMsg.checkStatus()) {
- return;
- }
-
- if (scheduledExecutorService == null) {
- scheduledExecutorService = SpringBeanFactory.getBean("scheduledTask", ScheduledExecutorService.class);
- reConnectManager = SpringBeanFactory.getBean(ReConnectManager.class);
- }
- log.info("客户端断开了,重新连接!");
- reConnectManager.reConnect(ctx);
- }
-
- @Override
- protected void channelRead0(ChannelHandlerContext ctx, CIMResponseProto.CIMResProtocol msg) throws Exception {
- if (echoService == null) {
- echoService = SpringBeanFactory.getBean(EchoServiceImpl.class);
- }
-
-
- //心跳更新时间
- if (msg.getType() == Constants.CommandType.PING) {
- //LOGGER.info("收到服务端心跳!!!");
- NettyAttrUtil.updateReaderTime(ctx.channel(), System.currentTimeMillis());
- }
-
- if (msg.getType() != Constants.CommandType.PING) {
- //回调消息
- callBackMsg(msg.getResMsg());
-
- //将消息中的 emoji 表情格式化为 Unicode 编码以便在终端可以显示
- String response = EmojiParser.parseToUnicode(msg.getResMsg());
- echoService.echo(response);
- }
-
-
- }
-
- /**
- * 回调消息
- *
- * @param msg
- */
- private void callBackMsg(String msg) {
- threadPoolExecutor = SpringBeanFactory.getBean("callBackThreadPool", ThreadPoolExecutor.class);
- threadPoolExecutor.execute(() -> {
- caller = SpringBeanFactory.getBean(MsgHandleCaller.class);
- caller.getMsgHandleListener().handle(msg);
- });
-
- }
-
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- //异常时断开连接
- cause.printStackTrace();
- ctx.close();
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/handle/MsgHandleCaller.java b/cim-client/src/main/java/com/crossoverjie/cim/client/handle/MsgHandleCaller.java
deleted file mode 100644
index 2f0f37ed..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/handle/MsgHandleCaller.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.crossoverjie.cim.client.handle;
-
-import com.crossoverjie.cim.client.service.CustomMsgHandleListener;
-
-/**
- * Function:消息回调 bean
- *
- * @author crossoverJie
- * Date: 2018/12/26 17:37
- * @since JDK 1.8
- */
-public class MsgHandleCaller {
-
- /**
- * 回调接口
- */
- private CustomMsgHandleListener msgHandleListener ;
-
- public MsgHandleCaller(CustomMsgHandleListener msgHandleListener) {
- this.msgHandleListener = msgHandleListener;
- }
-
- public CustomMsgHandleListener getMsgHandleListener() {
- return msgHandleListener;
- }
-
- public void setMsgHandleListener(CustomMsgHandleListener msgHandleListener) {
- this.msgHandleListener = msgHandleListener;
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/scanner/Scan.java b/cim-client/src/main/java/com/crossoverjie/cim/client/scanner/Scan.java
index 824bee0d..de9188ce 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/scanner/Scan.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/scanner/Scan.java
@@ -1,13 +1,11 @@
package com.crossoverjie.cim.client.scanner;
-import com.crossoverjie.cim.client.config.AppConfiguration;
-import com.crossoverjie.cim.client.service.EchoService;
+import com.crossoverjie.cim.client.sdk.Event;
import com.crossoverjie.cim.client.service.MsgHandle;
import com.crossoverjie.cim.client.service.MsgLogger;
import com.crossoverjie.cim.client.util.SpringBeanFactory;
-import com.vdurmont.emoji.EmojiParser;
-
import java.util.Scanner;
+import lombok.SneakyThrows;
/**
* Function:
@@ -19,47 +17,39 @@
public class Scan implements Runnable {
- /**
- * 系统参数
- */
- private AppConfiguration configuration;
-
- private MsgHandle msgHandle ;
-
- private MsgLogger msgLogger ;
+ private final MsgHandle msgHandle ;
- private EchoService echoService ;
+ private final MsgLogger msgLogger ;
+ private final Event event ;
public Scan() {
- this.configuration = SpringBeanFactory.getBean(AppConfiguration.class);
this.msgHandle = SpringBeanFactory.getBean(MsgHandle.class) ;
this.msgLogger = SpringBeanFactory.getBean(MsgLogger.class) ;
- this.echoService = SpringBeanFactory.getBean(EchoService.class) ;
+ this.event = SpringBeanFactory.getBean(Event.class) ;
}
+ @SneakyThrows
@Override
public void run() {
Scanner sc = new Scanner(System.in);
while (true) {
String msg = sc.nextLine();
- //检查消息
if (msgHandle.checkMsg(msg)) {
continue;
}
- //系统内置命令
+ // internal cmd
if (msgHandle.innerCommand(msg)){
continue;
}
- //真正的发送消息
msgHandle.sendMsg(msg) ;
- //写入聊天记录
+ // write to log
msgLogger.log(msg) ;
- echoService.echo(EmojiParser.parseToUnicode(msg));
+ event.info(msg);
}
}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/CustomMsgHandleListener.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/CustomMsgHandleListener.java
deleted file mode 100644
index ff92d9a1..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/CustomMsgHandleListener.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.crossoverjie.cim.client.service;
-
-/**
- * Function: 自定义消息回调
- *
- * @author crossoverJie
- * Date: 2018/12/26 17:24
- * @since JDK 1.8
- */
-public interface CustomMsgHandleListener {
-
- /**
- * 消息回调
- * @param msg
- */
- void handle(String msg);
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/EchoService.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/EchoService.java
deleted file mode 100644
index f4a57532..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/EchoService.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.crossoverjie.cim.client.service;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2019-08-27 22:35
- * @since JDK 1.8
- */
-public interface EchoService {
-
- /**
- * echo msg to terminal
- * @param msg message
- * @param replace
- */
- void echo(String msg, Object... replace) ;
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/InnerCommand.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/InnerCommand.java
index 77b704d9..3ea54802 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/InnerCommand.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/InnerCommand.java
@@ -13,5 +13,5 @@ public interface InnerCommand {
* 执行
* @param msg
*/
- void process(String msg) ;
+ void process(String msg) throws Exception;
}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/MsgHandle.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/MsgHandle.java
index 8af1e805..358e55d8 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/MsgHandle.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/MsgHandle.java
@@ -1,67 +1,50 @@
package com.crossoverjie.cim.client.service;
-import com.crossoverjie.cim.client.vo.req.GroupReqVO;
-import com.crossoverjie.cim.client.vo.req.P2PReqVO;
+import com.crossoverjie.cim.route.api.vo.req.ChatReqVO;
+import com.crossoverjie.cim.route.api.vo.req.P2PReqVO;
/**
* Function:消息处理器
*
* @author crossoverJie
- * Date: 2018/12/26 11:11
+ * Date: 2018/12/26 11:11
* @since JDK 1.8
*/
public interface MsgHandle {
/**
* 统一的发送接口,包含了 groupChat p2pChat
+ *
* @param msg
*/
- void sendMsg(String msg) ;
+ void sendMsg(String msg) throws Exception;
- /**
- * 群聊
- * @param groupReqVO 群聊消息 其中的 userId 为发送者的 userID
- * @throws Exception
- */
- void groupChat(GroupReqVO groupReqVO) throws Exception ;
- /**
- * 私聊
- * @param p2PReqVO 私聊请求
- * @throws Exception
- */
- void p2pChat(P2PReqVO p2PReqVO) throws Exception;
-
-
- // TODO: 2018/12/26 后续对消息的处理可以优化为责任链模式
/**
* 校验消息
+ *
* @param msg
* @return 不能为空,后续可以加上一些敏感词
* @throws Exception
*/
- boolean checkMsg(String msg) ;
+ boolean checkMsg(String msg);
/**
* 执行内部命令
+ *
* @param msg
* @return 是否应当跳过当前消息(包含了":" 就需要跳过)
*/
- boolean innerCommand(String msg) ;
-
+ boolean innerCommand(String msg) throws Exception;
- /**
- * 关闭系统
- */
- void shutdown() ;
/**
* 开启 AI 模式
*/
- void openAIModel() ;
+ void openAIModel();
/**
* 关闭 AI 模式
*/
- void closeAIModel() ;
+ void closeAIModel();
}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/MsgLogger.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/MsgLogger.java
index d2f27c44..822a1b23 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/MsgLogger.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/MsgLogger.java
@@ -10,7 +10,7 @@
public interface MsgLogger {
/**
- * 异步写入消息
+ * write log
* @param msg
*/
void log(String msg) ;
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/ReConnectManager.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/ReConnectManager.java
deleted file mode 100644
index 3e977e67..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/ReConnectManager.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.crossoverjie.cim.client.service;
-
-import com.crossoverjie.cim.client.thread.ReConnectJob;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import io.netty.channel.ChannelHandlerContext;
-import org.springframework.stereotype.Component;
-
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2020-04-15 00:26
- * @since JDK 1.8
- */
-@Component
-public final class ReConnectManager {
-
- private ScheduledExecutorService scheduledExecutorService;
-
- /**
- * Trigger reconnect job
- * @param ctx
- */
- public void reConnect(ChannelHandlerContext ctx) {
- buildExecutor() ;
- scheduledExecutorService.scheduleAtFixedRate(new ReConnectJob(ctx),0,10, TimeUnit.SECONDS) ;
- }
-
- /**
- * Close reconnect job if reconnect success.
- */
- public void reConnectSuccess(){
- scheduledExecutorService.shutdown();
- }
-
-
- /***
- * build an thread executor
- * @return
- */
- private ScheduledExecutorService buildExecutor() {
- if (scheduledExecutorService == null || scheduledExecutorService.isShutdown()) {
- ThreadFactory sche = new ThreadFactoryBuilder()
- .setNameFormat("reConnect-job-%d")
- .setDaemon(true)
- .build();
- scheduledExecutorService = new ScheduledThreadPoolExecutor(1, sche);
- return scheduledExecutorService;
- } else {
- return scheduledExecutorService;
- }
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/RouteRequest.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/RouteRequest.java
deleted file mode 100644
index 33286f4a..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/RouteRequest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.crossoverjie.cim.client.service;
-
-import com.crossoverjie.cim.client.vo.req.GroupReqVO;
-import com.crossoverjie.cim.client.vo.req.LoginReqVO;
-import com.crossoverjie.cim.client.vo.req.P2PReqVO;
-import com.crossoverjie.cim.client.vo.res.CIMServerResVO;
-import com.crossoverjie.cim.client.vo.res.OnlineUsersResVO;
-
-import java.util.List;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2018/12/22 22:26
- * @since JDK 1.8
- */
-public interface RouteRequest {
-
- /**
- * 群发消息
- * @param groupReqVO 消息
- * @throws Exception
- */
- void sendGroupMsg(GroupReqVO groupReqVO) throws Exception;
-
-
- /**
- * 私聊
- * @param p2PReqVO
- * @throws Exception
- */
- void sendP2PMsg(P2PReqVO p2PReqVO)throws Exception;
-
- /**
- * 获取服务器
- * @return 服务ip+port
- * @param loginReqVO
- * @throws Exception
- */
- CIMServerResVO.ServerInfo getCIMServer(LoginReqVO loginReqVO) throws Exception;
-
- /**
- * 获取所有在线用户
- * @return
- * @throws Exception
- */
- List onlineUsers()throws Exception ;
-
-
- void offLine() ;
-
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/ShutDownMsg.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/ShutDownSign.java
similarity index 85%
rename from cim-client/src/main/java/com/crossoverjie/cim/client/service/ShutDownMsg.java
rename to cim-client/src/main/java/com/crossoverjie/cim/client/service/ShutDownSign.java
index abebc7df..d7bd7088 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/ShutDownMsg.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/ShutDownSign.java
@@ -10,11 +10,11 @@
* @since JDK 1.8
*/
@Component
-public class ShutDownMsg {
+public class ShutDownSign {
private boolean isCommand ;
/**
- * 置为用户主动退出状态
+ * Set user exit sign.
*/
public void shutdown(){
isCommand = true ;
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/AsyncMsgLogger.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/AsyncMsgLogger.java
index 5dc10db9..3e87ad8a 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/AsyncMsgLogger.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/AsyncMsgLogger.java
@@ -2,6 +2,10 @@
import com.crossoverjie.cim.client.config.AppConfiguration;
import com.crossoverjie.cim.client.service.MsgLogger;
+import jakarta.annotation.Resource;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -33,17 +37,17 @@ public class AsyncMsgLogger implements MsgLogger {
* The default buffer size.
*/
private static final int DEFAULT_QUEUE_SIZE = 16;
- private BlockingQueue blockingQueue = new ArrayBlockingQueue(DEFAULT_QUEUE_SIZE);
+ private final BlockingQueue blockingQueue = new ArrayBlockingQueue(DEFAULT_QUEUE_SIZE);
private volatile boolean started = false;
- private Worker worker = new Worker();
+ private final Worker worker = new Worker();
- @Autowired
+ @Resource
private AppConfiguration appConfiguration;
@Override
public void log(String msg) {
- //开始消费
+ // start worker
startMsgLogger();
try {
// TODO: 2019/1/6 消息堆满是否阻塞线程?
@@ -88,9 +92,9 @@ private void writeLog(String msg) {
Files.createDirectories(Paths.get(dir));
}
- List lines = Arrays.asList(msg);
+ List lines = Collections.singletonList(msg);
- Files.write(file, lines, Charset.forName("UTF-8"), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
+ Files.write(file, lines, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.APPEND);
} catch (IOException e) {
log.info("IOException", e);
}
@@ -98,7 +102,7 @@ private void writeLog(String msg) {
}
/**
- * 开始工作
+ * Begin worker
*/
private void startMsgLogger() {
if (started) {
@@ -125,8 +129,9 @@ public String query(String key) {
Path path = Paths.get(appConfiguration.getMsgLoggerPath() + appConfiguration.getUserName() + "/");
try {
+ @Cleanup
Stream list = Files.list(path);
- List collect = list.collect(Collectors.toList());
+ List collect = list.toList();
for (Path file : collect) {
List strings = Files.readAllLines(file);
for (String msg : strings) {
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/ClientHeartBeatHandlerImpl.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/ClientHeartBeatHandlerImpl.java
deleted file mode 100644
index ed5b21bd..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/ClientHeartBeatHandlerImpl.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.crossoverjie.cim.client.service.impl;
-
-import com.crossoverjie.cim.client.client.CIMClient;
-import com.crossoverjie.cim.client.thread.ContextHolder;
-import com.crossoverjie.cim.common.kit.HeartBeatHandler;
-import io.netty.channel.ChannelHandlerContext;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2019-01-20 17:16
- * @since JDK 1.8
- */
-@Service
-public class ClientHeartBeatHandlerImpl implements HeartBeatHandler {
-
- @Autowired
- private CIMClient cimClient;
-
-
- @Override
- public void process(ChannelHandlerContext ctx) throws Exception {
-
- //重连
- ContextHolder.setReconnect(true);
- cimClient.reconnect();
-
- }
-
-
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/ClientInfo.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/ClientInfo.java
deleted file mode 100644
index eedb2de8..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/ClientInfo.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.crossoverjie.cim.client.service.impl;
-
-
-import org.springframework.stereotype.Component;
-
-import java.util.Date;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2019-01-21 23:35
- * @since JDK 1.8
- */
-@Component
-public class ClientInfo {
-
- private Info info = new Info() ;
-
- public Info get(){
- return info ;
- }
-
- public ClientInfo saveUserInfo(long userId,String userName){
- info.setUserId(userId);
- info.setUserName(userName);
- return this;
- }
-
-
- public ClientInfo saveServiceInfo(String serviceInfo){
- info.setServiceInfo(serviceInfo);
- return this;
- }
-
- public ClientInfo saveStartDate(){
- info.setStartDate(new Date());
- return this;
- }
-
- public class Info{
- private String userName;
- private long userId ;
- private String serviceInfo ;
- private Date startDate ;
-
- public Info() {
- }
-
- public String getUserName() {
- return userName;
- }
-
- public void setUserName(String userName) {
- this.userName = userName;
- }
-
- public long getUserId() {
- return userId;
- }
-
- public void setUserId(long userId) {
- this.userId = userId;
- }
-
- public String getServiceInfo() {
- return serviceInfo;
- }
-
- public void setServiceInfo(String serviceInfo) {
- this.serviceInfo = serviceInfo;
- }
-
- public Date getStartDate() {
- return startDate;
- }
-
- public void setStartDate(Date startDate) {
- this.startDate = startDate;
- }
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/EchoServiceImpl.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/EchoServiceImpl.java
index de9f0d25..2dce9ebb 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/EchoServiceImpl.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/EchoServiceImpl.java
@@ -1,12 +1,14 @@
package com.crossoverjie.cim.client.service.impl;
import com.crossoverjie.cim.client.config.AppConfiguration;
-import com.crossoverjie.cim.client.service.EchoService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
+import com.crossoverjie.cim.client.sdk.Client;
+import com.crossoverjie.cim.client.sdk.Event;
+import com.crossoverjie.cim.client.service.MsgLogger;
+import com.vdurmont.emoji.EmojiParser;
+import jakarta.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalTime;
+import org.springframework.stereotype.Service;
/**
* Function:
@@ -16,16 +18,26 @@
* @since JDK 1.8
*/
@Service
-public class EchoServiceImpl implements EchoService {
+public class EchoServiceImpl implements Event {
private static final String PREFIX = "$";
- @Autowired
+ @Resource
private AppConfiguration appConfiguration;
+ @Resource
+ private MsgLogger msgLogger;
+
@Override
- public void echo(String msg, Object... replace) {
- String date = LocalDate.now().toString() + " " + LocalTime.now().withNano(0).toString();
+ public void debug(String msg, Object... replace) {
+ msgLogger.log(String.format("Debug[%s]", msg));
+ }
+
+ @Override
+ public void info(String msg, Object... replace) {
+ // Make terminal can display the emoji
+ msg = EmojiParser.parseToUnicode(msg);
+ String date = LocalDate.now() + " " + LocalTime.now().withNano(0).toString();
msg = "[" + date + "] \033[31;4m" + appConfiguration.getUserName() + PREFIX + "\033[0m" + " " + msg;
@@ -34,6 +46,21 @@ public void echo(String msg, Object... replace) {
System.out.println(log);
}
+ @Override
+ public void warn(String msg, Object... replace) {
+ info(String.format("Warn##%s##", msg), replace);
+ }
+
+ @Override
+ public void error(String msg, Object... replace) {
+ info(String.format("Error!!%s!!", msg), replace);
+ }
+
+ @Override
+ public void fatal(Client client) {
+ info("{} fatal error, shutdown client", client.getAuth());
+ }
+
/**
* print msg
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/MsgCallBackListener.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/MsgCallBackListener.java
index 5eae7a2e..040ef0fd 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/MsgCallBackListener.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/MsgCallBackListener.java
@@ -1,27 +1,35 @@
package com.crossoverjie.cim.client.service.impl;
-import com.crossoverjie.cim.client.service.CustomMsgHandleListener;
+import com.crossoverjie.cim.client.sdk.Client;
+import com.crossoverjie.cim.client.sdk.Event;
+import com.crossoverjie.cim.client.sdk.io.MessageListener;
import com.crossoverjie.cim.client.service.MsgLogger;
-import com.crossoverjie.cim.client.util.SpringBeanFactory;
+import com.crossoverjie.cim.common.constant.Constants;
+import java.util.Map;
/**
* Function:自定义收到消息回调
*
* @author crossoverJie
- * Date: 2019/1/6 17:49
+ * Date: 2019/1/6 17:49
* @since JDK 1.8
*/
-public class MsgCallBackListener implements CustomMsgHandleListener {
+public class MsgCallBackListener implements MessageListener {
- private MsgLogger msgLogger ;
+ private final MsgLogger msgLogger;
+ private final Event event;
- public MsgCallBackListener() {
- this.msgLogger = SpringBeanFactory.getBean(MsgLogger.class) ;
+ public MsgCallBackListener(MsgLogger msgLogger, Event event) {
+ this.msgLogger = msgLogger;
+ this.event = event;
}
+
@Override
- public void handle(String msg) {
- msgLogger.log(msg) ;
+ public void received(Client client, Map properties, String msg) {
+ String sendUserName = properties.getOrDefault(Constants.MetaKey.USER_NAME, "nobody");
+ this.msgLogger.log(sendUserName + ":" + msg);
+ this.event.info(sendUserName + ":" + msg);
}
}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/MsgHandler.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/MsgHandler.java
index a71ec1da..32201763 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/MsgHandler.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/MsgHandler.java
@@ -1,22 +1,15 @@
package com.crossoverjie.cim.client.service.impl;
-import com.crossoverjie.cim.client.config.AppConfiguration;
+import com.crossoverjie.cim.client.sdk.Client;
import com.crossoverjie.cim.client.service.InnerCommand;
import com.crossoverjie.cim.client.service.InnerCommandContext;
import com.crossoverjie.cim.client.service.MsgHandle;
-import com.crossoverjie.cim.client.service.MsgLogger;
-import com.crossoverjie.cim.client.service.RouteRequest;
-import com.crossoverjie.cim.client.vo.req.GroupReqVO;
-import com.crossoverjie.cim.client.vo.req.P2PReqVO;
import com.crossoverjie.cim.common.util.StringUtil;
+import com.crossoverjie.cim.route.api.vo.req.P2PReqVO;
+import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import jakarta.annotation.Resource;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
/**
* Function:
*
@@ -27,29 +20,18 @@
@Slf4j
@Service
public class MsgHandler implements MsgHandle {
- @Autowired
- private RouteRequest routeRequest;
-
- @Autowired
- private AppConfiguration configuration;
-
- @Resource(name = "callBackThreadPool")
- private ThreadPoolExecutor executor;
-
-
- @Autowired
- private MsgLogger msgLogger;
- @Autowired
- private ClientInfo clientInfo;
- @Autowired
+ @Resource
private InnerCommandContext innerCommandContext ;
+ @Resource
+ private Client client;
+
private boolean aiModel = false;
@Override
- public void sendMsg(String msg) {
+ public void sendMsg(String msg) throws Exception {
if (aiModel) {
aiChat(msg);
} else {
@@ -57,33 +39,16 @@ public void sendMsg(String msg) {
}
}
- /**
- * 正常聊天
- *
- * @param msg
- */
- private void normalChat(String msg) {
+ private void normalChat(String msg) throws Exception {
String[] totalMsg = msg.split(";;");
if (totalMsg.length > 1) {
- //私聊
P2PReqVO p2PReqVO = new P2PReqVO();
- p2PReqVO.setUserId(configuration.getUserId());
p2PReqVO.setReceiveUserId(Long.parseLong(totalMsg[0]));
p2PReqVO.setMsg(totalMsg[1]);
- try {
- p2pChat(p2PReqVO);
- } catch (Exception e) {
- log.error("Exception", e);
- }
+ client.sendP2P(p2PReqVO);
} else {
- //群聊
- GroupReqVO groupReqVO = new GroupReqVO(configuration.getUserId(), msg);
- try {
- groupChat(groupReqVO);
- } catch (Exception e) {
- log.error("Exception", e);
- }
+ client.sendGroup(msg);
}
}
@@ -101,18 +66,6 @@ private void aiChat(String msg) {
System.out.println("AI:\033[31;4m" + msg + "\033[0m");
}
- @Override
- public void groupChat(GroupReqVO groupReqVO) throws Exception {
- routeRequest.sendGroupMsg(groupReqVO);
- }
-
- @Override
- public void p2pChat(P2PReqVO p2PReqVO) throws Exception {
-
- routeRequest.sendP2PMsg(p2PReqVO);
-
- }
-
@Override
public boolean checkMsg(String msg) {
if (StringUtil.isEmpty(msg)) {
@@ -123,7 +76,7 @@ public boolean checkMsg(String msg) {
}
@Override
- public boolean innerCommand(String msg) {
+ public boolean innerCommand(String msg) throws Exception {
if (msg.startsWith(":")) {
@@ -135,28 +88,6 @@ public boolean innerCommand(String msg) {
} else {
return false;
}
-
-
- }
-
- /**
- * 关闭系统
- */
- @Override
- public void shutdown() {
- log.info("系统关闭中。。。。");
- routeRequest.offLine();
- msgLogger.stop();
- executor.shutdown();
- try {
- while (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
- log.info("线程池关闭中。。。。");
- }
-// shutdownService.closeCIMClient();
- } catch (InterruptedException e) {
- log.error("InterruptedException", e);
- }
- System.exit(0);
}
@Override
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/RouteRequestImpl.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/RouteRequestImpl.java
deleted file mode 100644
index 0cfe2462..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/RouteRequestImpl.java
+++ /dev/null
@@ -1,162 +0,0 @@
-package com.crossoverjie.cim.client.service.impl;
-
-import com.alibaba.fastjson.JSON;
-import com.crossoverjie.cim.client.config.AppConfiguration;
-import com.crossoverjie.cim.client.service.EchoService;
-import com.crossoverjie.cim.client.service.RouteRequest;
-import com.crossoverjie.cim.client.thread.ContextHolder;
-import com.crossoverjie.cim.client.vo.req.GroupReqVO;
-import com.crossoverjie.cim.client.vo.req.LoginReqVO;
-import com.crossoverjie.cim.client.vo.req.P2PReqVO;
-import com.crossoverjie.cim.client.vo.res.CIMServerResVO;
-import com.crossoverjie.cim.client.vo.res.OnlineUsersResVO;
-import com.crossoverjie.cim.common.core.proxy.ProxyManager;
-import com.crossoverjie.cim.common.enums.StatusEnum;
-import com.crossoverjie.cim.common.exception.CIMException;
-import com.crossoverjie.cim.common.res.BaseResponse;
-import com.crossoverjie.cim.route.api.RouteApi;
-import com.crossoverjie.cim.route.api.vo.req.ChatReqVO;
-import lombok.extern.slf4j.Slf4j;
-import okhttp3.OkHttpClient;
-import okhttp3.Response;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2018/12/22 22:27
- * @since JDK 1.8
- */
-@Slf4j
-@Service
-public class RouteRequestImpl implements RouteRequest {
-
- @Autowired
- private OkHttpClient okHttpClient ;
-
- @Value("${cim.route.url}")
- private String routeUrl ;
-
- @Autowired
- private EchoService echoService ;
-
-
- @Autowired
- private AppConfiguration appConfiguration ;
-
- @Override
- public void sendGroupMsg(GroupReqVO groupReqVO) throws Exception {
- RouteApi routeApi = new ProxyManager<>(RouteApi.class, routeUrl, okHttpClient).getInstance();
- ChatReqVO chatReqVO = new ChatReqVO(groupReqVO.getUserId(), groupReqVO.getMsg()) ;
- Response response = null;
- try {
- response = (Response)routeApi.groupRoute(chatReqVO);
- }catch (Exception e){
- log.error("exception",e);
- }finally {
- response.body().close();
- }
- }
-
- @Override
- public void sendP2PMsg(P2PReqVO p2PReqVO) throws Exception {
- RouteApi routeApi = new ProxyManager<>(RouteApi.class, routeUrl, okHttpClient).getInstance();
- com.crossoverjie.cim.route.api.vo.req.P2PReqVO vo = new com.crossoverjie.cim.route.api.vo.req.P2PReqVO() ;
- vo.setMsg(p2PReqVO.getMsg());
- vo.setReceiveUserId(p2PReqVO.getReceiveUserId());
- vo.setUserId(p2PReqVO.getUserId());
-
- Response response = null;
- try {
- response = (Response) routeApi.p2pRoute(vo);
- String json = response.body().string() ;
- BaseResponse baseResponse = JSON.parseObject(json, BaseResponse.class);
-
- // account offline.
- if (baseResponse.getCode().equals(StatusEnum.OFF_LINE.getCode())){
- log.error(p2PReqVO.getReceiveUserId() + ":" + StatusEnum.OFF_LINE.getMessage());
- }
-
- }catch (Exception e){
- log.error("exception",e);
- }finally {
- response.body().close();
- }
- }
-
- @Override
- public CIMServerResVO.ServerInfo getCIMServer(LoginReqVO loginReqVO) throws Exception {
-
- RouteApi routeApi = new ProxyManager<>(RouteApi.class, routeUrl, okHttpClient).getInstance();
- com.crossoverjie.cim.route.api.vo.req.LoginReqVO vo = new com.crossoverjie.cim.route.api.vo.req.LoginReqVO() ;
- vo.setUserId(loginReqVO.getUserId());
- vo.setUserName(loginReqVO.getUserName());
-
- Response response = null;
- CIMServerResVO cimServerResVO = null;
- try {
- response = (Response) routeApi.login(vo);
- String json = response.body().string();
- cimServerResVO = JSON.parseObject(json, CIMServerResVO.class);
-
- //重复失败
- if (!cimServerResVO.getCode().equals(StatusEnum.SUCCESS.getCode())){
- echoService.echo(cimServerResVO.getMessage());
-
- // when client in reConnect state, could not exit.
- if (ContextHolder.getReconnect()){
- echoService.echo("###{}###", StatusEnum.RECONNECT_FAIL.getMessage());
- throw new CIMException(StatusEnum.RECONNECT_FAIL);
- }
-
- System.exit(-1);
- }
-
- }catch (Exception e){
- log.error("exception",e);
- }finally {
- response.body().close();
- }
-
- return cimServerResVO.getDataBody();
- }
-
- @Override
- public List onlineUsers() throws Exception{
- RouteApi routeApi = new ProxyManager<>(RouteApi.class, routeUrl, okHttpClient).getInstance();
-
- Response response = null;
- OnlineUsersResVO onlineUsersResVO = null;
- try {
- response = (Response) routeApi.onlineUser();
- String json = response.body().string() ;
- onlineUsersResVO = JSON.parseObject(json, OnlineUsersResVO.class);
-
- }catch (Exception e){
- log.error("exception",e);
- }finally {
- response.body().close();
- }
-
- return onlineUsersResVO.getDataBody();
- }
-
- @Override
- public void offLine() {
- RouteApi routeApi = new ProxyManager<>(RouteApi.class, routeUrl, okHttpClient).getInstance();
- ChatReqVO vo = new ChatReqVO(appConfiguration.getUserId(), "offLine") ;
- Response response = null;
- try {
- response = (Response) routeApi.offLine(vo);
- } catch (Exception e) {
- log.error("exception",e);
- } finally {
- response.body().close();
- }
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/CloseAIModelCommand.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/CloseAIModelCommand.java
index 37b85f55..318ff476 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/CloseAIModelCommand.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/CloseAIModelCommand.java
@@ -1,9 +1,9 @@
package com.crossoverjie.cim.client.service.impl.command;
-import com.crossoverjie.cim.client.service.EchoService;
+import com.crossoverjie.cim.client.sdk.Event;
import com.crossoverjie.cim.client.service.InnerCommand;
import com.crossoverjie.cim.client.service.MsgHandle;
-import org.springframework.beans.factory.annotation.Autowired;
+import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
/**
@@ -17,16 +17,16 @@
public class CloseAIModelCommand implements InnerCommand {
- @Autowired
+ @Resource
private MsgHandle msgHandle ;
- @Autowired
- private EchoService echoService ;
+ @Resource
+ private Event event ;
@Override
public void process(String msg) {
msgHandle.closeAIModel();
- echoService.echo("\033[31;4m" + "。゚(゚´ω`゚)゚。 AI 下线了!" + "\033[0m");
+ event.info("\033[31;4m" + "。゚(゚´ω`゚)゚。 AI 下线了!" + "\033[0m");
}
}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/DelayMsgCommand.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/DelayMsgCommand.java
index c5f37e4a..b69a1c5b 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/DelayMsgCommand.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/DelayMsgCommand.java
@@ -1,11 +1,11 @@
package com.crossoverjie.cim.client.service.impl.command;
-import com.crossoverjie.cim.client.service.EchoService;
+import com.crossoverjie.cim.client.sdk.Event;
import com.crossoverjie.cim.client.service.InnerCommand;
import com.crossoverjie.cim.client.service.MsgHandle;
import com.crossoverjie.cim.common.data.construct.RingBufferWheel;
-import com.vdurmont.emoji.EmojiParser;
-import org.springframework.beans.factory.annotation.Autowired;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
@@ -16,31 +16,32 @@
* @since JDK 1.8
*/
@Service
+@Slf4j
public class DelayMsgCommand implements InnerCommand {
- @Autowired
- private EchoService echoService ;
+ @Resource
+ private Event event;
- @Autowired
+ @Resource
private MsgHandle msgHandle ;
- @Autowired
+ @Resource
private RingBufferWheel ringBufferWheel ;
@Override
public void process(String msg) {
if (msg.split(" ").length <=2){
- echoService.echo("incorrect commond, :delay [msg] [delayTime]") ;
+ event.info("incorrect commond, :delay [msg] [delayTime]") ;
return ;
}
String message = msg.split(" ")[1] ;
- Integer delayTime = Integer.valueOf(msg.split(" ")[2]);
+ int delayTime = Integer.parseInt(msg.split(" ")[2]);
RingBufferWheel.Task task = new DelayMsgJob(message) ;
task.setKey(delayTime);
ringBufferWheel.addTask(task);
- echoService.echo(EmojiParser.parseToUnicode(msg));
+ event.info(msg);
}
@@ -55,7 +56,11 @@ public DelayMsgJob(String msg) {
@Override
public void run() {
- msgHandle.sendMsg(msg);
+ try {
+ msgHandle.sendMsg(msg);
+ } catch (Exception e) {
+ log.error("Delay message send error",e);
+ }
}
}
}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/EchoInfoCommand.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/EchoInfoCommand.java
index b6891692..e5bce11b 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/EchoInfoCommand.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/EchoInfoCommand.java
@@ -1,9 +1,9 @@
package com.crossoverjie.cim.client.service.impl.command;
-import com.crossoverjie.cim.client.service.EchoService;
+import com.crossoverjie.cim.client.sdk.Client;
+import com.crossoverjie.cim.client.sdk.Event;
import com.crossoverjie.cim.client.service.InnerCommand;
-import com.crossoverjie.cim.client.service.impl.ClientInfo;
-import org.springframework.beans.factory.annotation.Autowired;
+import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
/**
@@ -16,16 +16,16 @@
@Service
public class EchoInfoCommand implements InnerCommand {
- @Autowired
- private ClientInfo clientInfo;
+ @Resource
+ private Client client;
- @Autowired
- private EchoService echoService ;
+ @Resource
+ private Event event ;
@Override
public void process(String msg) {
- echoService.echo("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
- echoService.echo("client info={}", clientInfo.get().getUserName());
- echoService.echo("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
+ event.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
+ event.info("client info={}", client.getAuth());
+ event.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/EmojiCommand.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/EmojiCommand.java
index 943a743a..b94e93de 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/EmojiCommand.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/EmojiCommand.java
@@ -1,14 +1,13 @@
package com.crossoverjie.cim.client.service.impl.command;
-import com.crossoverjie.cim.client.service.EchoService;
+import com.crossoverjie.cim.client.sdk.Event;
import com.crossoverjie.cim.client.service.InnerCommand;
import com.vdurmont.emoji.Emoji;
import com.vdurmont.emoji.EmojiManager;
import com.vdurmont.emoji.EmojiParser;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
+import jakarta.annotation.Resource;
import java.util.List;
+import org.springframework.stereotype.Service;
/**
* Function:
@@ -20,24 +19,24 @@
@Service
public class EmojiCommand implements InnerCommand {
- @Autowired
- private EchoService echoService ;
+ @Resource
+ private Event event ;
@Override
public void process(String msg) {
if (msg.split(" ").length <=1){
- echoService.echo("incorrect commond, :emoji [option]") ;
+ event.info("incorrect commond, :emoji [option]") ;
return ;
}
String value = msg.split(" ")[1];
if (value != null) {
- Integer index = Integer.parseInt(value);
+ int index = Integer.parseInt(value);
List all = (List) EmojiManager.getAll();
all = all.subList(5 * index, 5 * index + 5);
for (Emoji emoji : all) {
- echoService.echo(EmojiParser.parseToAliases(emoji.getUnicode()) + "--->" + emoji.getUnicode());
+ event.info(EmojiParser.parseToAliases(emoji.getUnicode()) + "--->" + emoji.getUnicode());
}
}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/PrefixSearchCommand.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/PrefixSearchCommand.java
index e3270a9b..a0082bf8 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/PrefixSearchCommand.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/PrefixSearchCommand.java
@@ -1,16 +1,16 @@
package com.crossoverjie.cim.client.service.impl.command;
-import com.crossoverjie.cim.client.service.EchoService;
+import com.crossoverjie.cim.client.sdk.Client;
+import com.crossoverjie.cim.client.sdk.Event;
import com.crossoverjie.cim.client.service.InnerCommand;
-import com.crossoverjie.cim.client.service.RouteRequest;
-import com.crossoverjie.cim.client.vo.res.OnlineUsersResVO;
import com.crossoverjie.cim.common.data.construct.TrieTree;
+import com.crossoverjie.cim.common.pojo.CIMUserInfo;
+import jakarta.annotation.Resource;
+import java.util.List;
+import java.util.Set;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import java.util.List;
-
/**
* Function:
*
@@ -23,17 +23,17 @@
public class PrefixSearchCommand implements InnerCommand {
- @Autowired
- private RouteRequest routeRequest ;
- @Autowired
- private EchoService echoService ;
+ @Resource
+ private Client client ;
+ @Resource
+ private Event event ;
@Override
public void process(String msg) {
try {
- List onlineUsers = routeRequest.onlineUsers();
+ Set onlineUsers = client.getOnlineUser();
TrieTree trieTree = new TrieTree();
- for (OnlineUsersResVO.DataBodyBean onlineUser : onlineUsers) {
+ for (CIMUserInfo onlineUser : onlineUsers) {
trieTree.insert(onlineUser.getUserName());
}
@@ -43,7 +43,7 @@ public void process(String msg) {
for (String res : list) {
res = res.replace(key, "\033[31;4m" + key + "\033[0m");
- echoService.echo(res) ;
+ event.info(res) ;
}
} catch (Exception e) {
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/PrintAllCommand.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/PrintAllCommand.java
index 11807815..f597ba24 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/PrintAllCommand.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/PrintAllCommand.java
@@ -1,12 +1,11 @@
package com.crossoverjie.cim.client.service.impl.command;
-import com.crossoverjie.cim.client.service.EchoService;
+import com.crossoverjie.cim.client.sdk.Event;
import com.crossoverjie.cim.client.service.InnerCommand;
import com.crossoverjie.cim.common.enums.SystemCommandEnum;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
+import jakarta.annotation.Resource;
import java.util.Map;
+import org.springframework.stereotype.Service;
/**
* Function:
@@ -19,18 +18,18 @@
public class PrintAllCommand implements InnerCommand {
- @Autowired
- private EchoService echoService ;
+ @Resource
+ private Event event ;
@Override
public void process(String msg) {
Map allStatusCode = SystemCommandEnum.getAllStatusCode();
- echoService.echo("====================================");
+ event.info("====================================");
for (Map.Entry stringStringEntry : allStatusCode.entrySet()) {
String key = stringStringEntry.getKey();
String value = stringStringEntry.getValue();
- echoService.echo(key + "----->" + value);
+ event.info(key + "----->" + value);
}
- echoService.echo("====================================");
+ event.info("====================================");
}
}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/PrintOnlineUsersCommand.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/PrintOnlineUsersCommand.java
index b015f0c7..f1cb2300 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/PrintOnlineUsersCommand.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/PrintOnlineUsersCommand.java
@@ -1,15 +1,14 @@
package com.crossoverjie.cim.client.service.impl.command;
-import com.crossoverjie.cim.client.service.EchoService;
+import com.crossoverjie.cim.client.sdk.Client;
+import com.crossoverjie.cim.client.sdk.Event;
import com.crossoverjie.cim.client.service.InnerCommand;
-import com.crossoverjie.cim.client.service.RouteRequest;
-import com.crossoverjie.cim.client.vo.res.OnlineUsersResVO;
+import com.crossoverjie.cim.common.pojo.CIMUserInfo;
+import jakarta.annotation.Resource;
+import java.util.Set;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import java.util.List;
-
/**
* Function:
*
@@ -21,22 +20,22 @@
@Service
public class PrintOnlineUsersCommand implements InnerCommand {
- @Autowired
- private RouteRequest routeRequest ;
+ @Resource
+ private Client client ;
- @Autowired
- private EchoService echoService ;
+ @Resource
+ private Event event ;
@Override
public void process(String msg) {
try {
- List onlineUsers = routeRequest.onlineUsers();
+ Set onlineUsers = client.getOnlineUser();
- echoService.echo("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
- for (OnlineUsersResVO.DataBodyBean onlineUser : onlineUsers) {
- echoService.echo("userId={}=====userName={}",onlineUser.getUserId(),onlineUser.getUserName());
+ event.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
+ for (CIMUserInfo onlineUser : onlineUsers) {
+ event.info("userId={}=====userName={}",onlineUser.getUserId(),onlineUser.getUserName());
}
- echoService.echo("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
+ event.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
} catch (Exception e) {
log.error("Exception", e);
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/QueryHistoryCommand.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/QueryHistoryCommand.java
index 61314460..586b0d3f 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/QueryHistoryCommand.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/QueryHistoryCommand.java
@@ -1,10 +1,10 @@
package com.crossoverjie.cim.client.service.impl.command;
-import com.crossoverjie.cim.client.service.EchoService;
+import com.crossoverjie.cim.client.sdk.Event;
import com.crossoverjie.cim.client.service.InnerCommand;
import com.crossoverjie.cim.client.service.MsgLogger;
+import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
@@ -18,11 +18,11 @@
@Service
public class QueryHistoryCommand implements InnerCommand {
- @Autowired
+ @Resource
private MsgLogger msgLogger ;
- @Autowired
- private EchoService echoService ;
+ @Resource
+ private Event event ;
@Override
public void process(String msg) {
@@ -31,6 +31,6 @@ public void process(String msg) {
return;
}
String res = msgLogger.query(split[1]);
- echoService.echo(res);
+ event.info(res);
}
}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/ShutDownCommand.java b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/ShutDownCommand.java
index f461add8..608a44b9 100644
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/ShutDownCommand.java
+++ b/cim-client/src/main/java/com/crossoverjie/cim/client/service/impl/command/ShutDownCommand.java
@@ -1,19 +1,17 @@
package com.crossoverjie.cim.client.service.impl.command;
-import com.crossoverjie.cim.client.client.CIMClient;
-import com.crossoverjie.cim.client.service.EchoService;
+import com.crossoverjie.cim.client.sdk.Client;
+import com.crossoverjie.cim.client.sdk.Event;
import com.crossoverjie.cim.client.service.InnerCommand;
import com.crossoverjie.cim.client.service.MsgLogger;
-import com.crossoverjie.cim.client.service.RouteRequest;
-import com.crossoverjie.cim.client.service.ShutDownMsg;
+import com.crossoverjie.cim.client.service.ShutDownSign;
import com.crossoverjie.cim.common.data.construct.RingBufferWheel;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
import jakarta.annotation.Resource;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.stereotype.Service;
/**
* Function:
@@ -24,47 +22,43 @@
*/
@Slf4j
@Service
+@ConditionalOnWebApplication
public class ShutDownCommand implements InnerCommand {
- @Autowired
- private RouteRequest routeRequest ;
-
- @Autowired
- private CIMClient cimClient;
+ @Resource
+ private Client cimClient;
- @Autowired
+ @Resource
private MsgLogger msgLogger;
@Resource(name = "callBackThreadPool")
private ThreadPoolExecutor callBackExecutor;
- @Autowired
- private EchoService echoService ;
-
+ @Resource
+ private Event event;
- @Autowired
- private ShutDownMsg shutDownMsg ;
+ @Resource
+ private ShutDownSign shutDownSign;
- @Autowired
+ @Resource
private RingBufferWheel ringBufferWheel ;
@Override
- public void process(String msg) {
- echoService.echo("cim client closing...");
- shutDownMsg.shutdown();
- routeRequest.offLine();
+ public void process(String msg) throws Exception {
+ event.info("cim client closing...");
+ cimClient.close();
+ shutDownSign.shutdown();
msgLogger.stop();
callBackExecutor.shutdown();
ringBufferWheel.stop(false);
try {
while (!callBackExecutor.awaitTermination(1, TimeUnit.SECONDS)) {
- echoService.echo("thread pool closing");
+ event.info("thread pool closing");
}
- cimClient.close();
- } catch (InterruptedException e) {
- log.error("InterruptedException", e);
+ } catch (Exception e) {
+ log.error("exception", e);
}
- echoService.echo("cim close success!");
+ event.info("cim close success!");
System.exit(0);
}
}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/thread/ContextHolder.java b/cim-client/src/main/java/com/crossoverjie/cim/client/thread/ContextHolder.java
deleted file mode 100644
index 5867e9b7..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/thread/ContextHolder.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.crossoverjie.cim.client.thread;
-
-/**
- * Function: Something about of client runtime sign.
- *
- * @author crossoverJie
- * Date: 2020-04-13 02:10
- * @since JDK 1.8
- */
-public class ContextHolder {
- private static final ThreadLocal IS_RECONNECT = new ThreadLocal<>() ;
-
- public static void setReconnect(boolean reconnect){
- IS_RECONNECT.set(reconnect);
- }
-
- public static Boolean getReconnect(){
- return IS_RECONNECT.get() ;
- }
-
- public static void clear(){
- IS_RECONNECT.remove();
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/thread/ReConnectJob.java b/cim-client/src/main/java/com/crossoverjie/cim/client/thread/ReConnectJob.java
deleted file mode 100644
index 3e148e7f..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/thread/ReConnectJob.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.crossoverjie.cim.client.thread;
-
-import com.crossoverjie.cim.client.service.impl.ClientHeartBeatHandlerImpl;
-import com.crossoverjie.cim.client.util.SpringBeanFactory;
-import com.crossoverjie.cim.common.kit.HeartBeatHandler;
-import io.netty.channel.ChannelHandlerContext;
-import lombok.extern.slf4j.Slf4j;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2019-01-20 21:35
- * @since JDK 1.8
- */
-@Slf4j
-public class ReConnectJob implements Runnable {
-
-
- private ChannelHandlerContext context ;
-
- private HeartBeatHandler heartBeatHandler ;
-
- public ReConnectJob(ChannelHandlerContext context) {
- this.context = context;
- this.heartBeatHandler = SpringBeanFactory.getBean(ClientHeartBeatHandlerImpl.class) ;
- }
-
- @Override
- public void run() {
- try {
- heartBeatHandler.process(context);
- } catch (Exception e) {
- log.error("Exception",e);
- }
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/GoogleProtocolVO.java b/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/GoogleProtocolVO.java
deleted file mode 100644
index a25a0afb..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/GoogleProtocolVO.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.crossoverjie.cim.client.vo.req;
-
-import com.crossoverjie.cim.common.req.BaseRequest;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotNull;
-
-/**
- * Function: Google Protocol 编解码发送
- *
- * @author crossoverJie
- * Date: 2018/05/21 15:56
- * @since JDK 1.8
- */
-public class GoogleProtocolVO extends BaseRequest {
- @NotNull(message = "requestId 不能为空")
- @Schema(requiredMode = Schema.RequiredMode.REQUIRED , description = "requestId", example = "123")
- private Integer requestId ;
-
- @NotNull(message = "msg 不能为空")
- @Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "msg", example = "hello")
- private String msg ;
-
- public String getMsg() {
- return msg;
- }
-
- public void setMsg(String msg) {
- this.msg = msg;
- }
-
- public Integer getRequestId() {
- return requestId;
- }
-
- public void setRequestId(Integer requestId) {
- this.requestId = requestId;
- }
-
- @Override
- public String toString() {
- return "GoogleProtocolVO{" +
- "requestId=" + requestId +
- ", msg='" + msg + '\'' +
- "} " + super.toString();
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/GroupReqVO.java b/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/GroupReqVO.java
deleted file mode 100644
index c9d2145e..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/GroupReqVO.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.crossoverjie.cim.client.vo.req;
-
-import com.crossoverjie.cim.common.req.BaseRequest;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotNull;
-
-/**
- * Function: 群发请求
- *
- * @author crossoverJie
- * Date: 2018/05/21 15:56
- * @since JDK 1.8
- */
-public class GroupReqVO extends BaseRequest {
-
- @NotNull(message = "userId 不能为空")
- @Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "消息发送者的 userId", example = "1545574049323")
- private Long userId ;
-
-
- @NotNull(message = "msg 不能为空")
- @Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "msg", example = "hello")
- private String msg ;
-
- public GroupReqVO(Long userId, String msg) {
- this.userId = userId;
- this.msg = msg;
- }
-
- public String getMsg() {
- return msg;
- }
-
- public void setMsg(String msg) {
- this.msg = msg;
- }
-
- public Long getUserId() {
- return userId;
- }
-
- public void setUserId(Long userId) {
- this.userId = userId;
- }
-
- @Override
- public String toString() {
- return "GroupReqVO{" +
- "userId=" + userId +
- ", msg='" + msg + '\'' +
- "} " + super.toString();
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/LoginReqVO.java b/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/LoginReqVO.java
deleted file mode 100644
index 66de629e..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/LoginReqVO.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.crossoverjie.cim.client.vo.req;
-
-import com.crossoverjie.cim.common.req.BaseRequest;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2018/12/23 22:30
- * @since JDK 1.8
- */
-public class LoginReqVO extends BaseRequest{
- private Long userId ;
- private String userName ;
-
- public LoginReqVO(Long userId, String userName) {
- this.userId = userId;
- this.userName = userName;
- }
-
- public Long getUserId() {
- return userId;
- }
-
- public void setUserId(Long userId) {
- this.userId = userId;
- }
-
- public String getUserName() {
- return userName;
- }
-
- public void setUserName(String userName) {
- this.userName = userName;
- }
-
- @Override
- public String toString() {
- return "LoginReqVO{" +
- "userId=" + userId +
- ", userName='" + userName + '\'' +
- "} " + super.toString();
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/P2PReqVO.java b/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/P2PReqVO.java
deleted file mode 100644
index 7b66dc41..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/P2PReqVO.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.crossoverjie.cim.client.vo.req;
-
-import com.crossoverjie.cim.common.req.BaseRequest;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotNull;
-
-/**
- * Function: 单聊请求
- *
- * @author crossoverJie
- * Date: 2018/05/21 15:56
- * @since JDK 1.8
- */
-public class P2PReqVO extends BaseRequest {
-
- @NotNull(message = "userId 不能为空")
- @Schema(requiredMode = Schema.RequiredMode.REQUIRED , description = "消息发送者的 userId", example = "1545574049323")
- private Long userId ;
-
-
- @NotNull(message = "userId 不能为空")
- @Schema(requiredMode = Schema.RequiredMode.REQUIRED , description = "消息接收者的 userId", example = "1545574049323")
- private Long receiveUserId ;
-
-
-
-
- @NotNull(message = "msg 不能为空")
- @Schema(requiredMode = Schema.RequiredMode.REQUIRED , description = "msg", example = "hello")
- private String msg ;
-
- public P2PReqVO() {
- }
-
- public P2PReqVO(Long userId, Long receiveUserId, String msg) {
- this.userId = userId;
- this.receiveUserId = receiveUserId;
- this.msg = msg;
- }
-
- public Long getReceiveUserId() {
- return receiveUserId;
- }
-
- public void setReceiveUserId(Long receiveUserId) {
- this.receiveUserId = receiveUserId;
- }
-
- public String getMsg() {
- return msg;
- }
-
- public void setMsg(String msg) {
- this.msg = msg;
- }
-
- public Long getUserId() {
- return userId;
- }
-
- public void setUserId(Long userId) {
- this.userId = userId;
- }
-
- @Override
- public String toString() {
- return "GroupReqVO{" +
- "userId=" + userId +
- ", msg='" + msg + '\'' +
- "} " + super.toString();
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/SendMsgReqVO.java b/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/SendMsgReqVO.java
deleted file mode 100644
index 8fe4c8e1..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/SendMsgReqVO.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.crossoverjie.cim.client.vo.req;
-
-import com.crossoverjie.cim.common.req.BaseRequest;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotNull;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2018/05/21 15:56
- * @since JDK 1.8
- */
-public class SendMsgReqVO extends BaseRequest {
-
- @NotNull(message = "msg 不能为空")
- @Schema(requiredMode = Schema.RequiredMode.REQUIRED , description = "msg", example = "hello")
- private String msg ;
-
- @NotNull(message = "userId 不能为空")
- @Schema(requiredMode = Schema.RequiredMode.REQUIRED , description = "userId", example = "11")
- private Long userId ;
-
- public String getMsg() {
- return msg;
- }
-
- public void setMsg(String msg) {
- this.msg = msg;
- }
-
- public long getUserId() {
- return userId;
- }
-
- public void setUserId(long userId) {
- this.userId = userId;
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/StringReqVO.java b/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/StringReqVO.java
deleted file mode 100644
index 36cc491a..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/req/StringReqVO.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.crossoverjie.cim.client.vo.req;
-
-import com.crossoverjie.cim.common.req.BaseRequest;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotNull;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2018/05/21 15:56
- * @since JDK 1.8
- */
-public class StringReqVO extends BaseRequest {
-
- @NotNull(message = "msg 不能为空")
- @Schema(requiredMode = Schema.RequiredMode.REQUIRED , description = "msg", example = "hello")
- private String msg ;
-
- public String getMsg() {
- return msg;
- }
-
- public void setMsg(String msg) {
- this.msg = msg;
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/res/CIMServerResVO.java b/cim-client/src/main/java/com/crossoverjie/cim/client/vo/res/CIMServerResVO.java
deleted file mode 100644
index 5382ea26..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/res/CIMServerResVO.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package com.crossoverjie.cim.client.vo.res;
-
-import java.io.Serializable;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2018/12/23 00:43
- * @since JDK 1.8
- */
-public class CIMServerResVO implements Serializable {
-
- /**
- * code : 9000
- * message : 成功
- * reqNo : null
- * dataBody : {"ip":"127.0.0.1","port":8081}
- */
-
- private String code;
- private String message;
- private Object reqNo;
- private ServerInfo dataBody;
-
- public String getCode() {
- return code;
- }
-
- public void setCode(String code) {
- this.code = code;
- }
-
- public String getMessage() {
- return message;
- }
-
- public void setMessage(String message) {
- this.message = message;
- }
-
- public Object getReqNo() {
- return reqNo;
- }
-
- public void setReqNo(Object reqNo) {
- this.reqNo = reqNo;
- }
-
- public ServerInfo getDataBody() {
- return dataBody;
- }
-
- public void setDataBody(ServerInfo dataBody) {
- this.dataBody = dataBody;
- }
-
- public static class ServerInfo {
- /**
- * ip : 127.0.0.1
- * port : 8081
- */
- private String ip ;
- private Integer cimServerPort;
- private Integer httpPort;
-
- public String getIp() {
- return ip;
- }
-
- public void setIp(String ip) {
- this.ip = ip;
- }
-
- public Integer getCimServerPort() {
- return cimServerPort;
- }
-
- public void setCimServerPort(Integer cimServerPort) {
- this.cimServerPort = cimServerPort;
- }
-
- public Integer getHttpPort() {
- return httpPort;
- }
-
- public void setHttpPort(Integer httpPort) {
- this.httpPort = httpPort;
- }
-
- @Override
- public String toString() {
- return "ServerInfo{" +
- "ip='" + ip + '\'' +
- ", cimServerPort=" + cimServerPort +
- ", httpPort=" + httpPort +
- '}';
- }
- }
-
-
- @Override
- public String toString() {
- return "CIMServerResVO{" +
- "code='" + code + '\'' +
- ", message='" + message + '\'' +
- ", reqNo=" + reqNo +
- ", dataBody=" + dataBody +
- '}';
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/res/OnlineUsersResVO.java b/cim-client/src/main/java/com/crossoverjie/cim/client/vo/res/OnlineUsersResVO.java
deleted file mode 100644
index 19658168..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/res/OnlineUsersResVO.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.crossoverjie.cim.client.vo.res;
-
-import java.util.List;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2018/12/26 23:17
- * @since JDK 1.8
- */
-public class OnlineUsersResVO {
-
-
- /**
- * code : 9000
- * message : 成功
- * reqNo : null
- * dataBody : [{"userId":1545574841528,"userName":"zhangsan"},{"userId":1545574871143,"userName":"crossoverJie"}]
- */
-
- private String code;
- private String message;
- private Object reqNo;
- private List dataBody;
-
- public String getCode() {
- return code;
- }
-
- public void setCode(String code) {
- this.code = code;
- }
-
- public String getMessage() {
- return message;
- }
-
- public void setMessage(String message) {
- this.message = message;
- }
-
- public Object getReqNo() {
- return reqNo;
- }
-
- public void setReqNo(Object reqNo) {
- this.reqNo = reqNo;
- }
-
- public List getDataBody() {
- return dataBody;
- }
-
- public void setDataBody(List dataBody) {
- this.dataBody = dataBody;
- }
-
- public static class DataBodyBean {
- /**
- * userId : 1545574841528
- * userName : zhangsan
- */
-
- private long userId;
- private String userName;
-
- public long getUserId() {
- return userId;
- }
-
- public void setUserId(long userId) {
- this.userId = userId;
- }
-
- public String getUserName() {
- return userName;
- }
-
- public void setUserName(String userName) {
- this.userName = userName;
- }
- }
-}
diff --git a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/res/SendMsgResVO.java b/cim-client/src/main/java/com/crossoverjie/cim/client/vo/res/SendMsgResVO.java
deleted file mode 100644
index 69160275..00000000
--- a/cim-client/src/main/java/com/crossoverjie/cim/client/vo/res/SendMsgResVO.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.crossoverjie.cim.client.vo.res;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2017/6/26 15:43
- * @since JDK 1.8
- */
-public class SendMsgResVO {
- private String msg ;
-
- public String getMsg() {
- return msg;
- }
-
- public void setMsg(String msg) {
- this.msg = msg;
- }
-}
diff --git a/cim-client/src/main/resources/application.yaml b/cim-client/src/main/resources/application.yaml
index f1b92859..862f1f59 100644
--- a/cim-client/src/main/resources/application.yaml
+++ b/cim-client/src/main/resources/application.yaml
@@ -1,37 +1,37 @@
-spring:
- application:
- name: cim-client
-
-# web port
-server:
- port: 8082
-
-logging:
- level:
- root: error
-
-# enable swagger
-springdoc:
- swagger-ui:
- enabled: true
-
-# log path
-cim:
- msg:
- logger:
- path: /opt/logs/cim/
- route:
- url: http://localhost:8083 # route url suggested that this is Nginx address
- user: # cim userId and userName
- id: 1722343979085
- userName: zhangsan
- callback:
- thread:
- queue:
- size: 2
- pool:
- size: 2
- heartbeat:
- time: 60 # cim heartbeat time (seconds)
- reconnect:
- count: 3
\ No newline at end of file
+spring:
+ application:
+ name: cim-client
+
+# web port
+server:
+ port: 8082
+
+logging:
+ level:
+ root: error
+
+# enable swagger
+springdoc:
+ swagger-ui:
+ enabled: true
+
+# log path
+cim:
+ msg:
+ logger:
+ path: /opt/logs/cim/
+ route:
+ url: http://localhost:8083 # route url suggested that this is Nginx address
+ user: # cim userId and userName
+ id: 1725714450795
+ userName: cj4
+ callback:
+ thread:
+ queue:
+ size: 2
+ pool:
+ size: 2
+ heartbeat:
+ time: 60 # cim heartbeat time (seconds)
+ reconnect:
+ count: 3
diff --git a/cim-client/src/main/resources/banner.txt b/cim-client/src/main/resources/banner.txt
index 97b15b91..c7e303f1 100644
--- a/cim-client/src/main/resources/banner.txt
+++ b/cim-client/src/main/resources/banner.txt
@@ -1,14 +1,7 @@
-
- ▄████▄ ██▓ ███▄ ▄███▓
-▒██▀ ▀█ ▓██▒▓██▒▀█▀ ██▒
-▒▓█ ▄ ▒██▒▓██ ▓██░
-▒▓▓▄ ▄██▒░██░▒██ ▒██
-▒ ▓███▀ ░░██░▒██▒ ░██▒
-░ ░▒ ▒ ░░▓ ░ ▒░ ░ ░
- ░ ▒ ▒ ░░ ░ ░
-░ ▒ ░░ ░
-░ ░ ░ ░
-░
+ _ ___ __
+ ____(_)_ _ ____/ (_)__ ___ / /_
+/ __/ / ' \ / __/ / / -_) _ \/ __/
+\__/_/_/_/_/ \__/_/_/\__/_//_/\__/
Power by @crossoverJie
diff --git a/cim-client/src/test/com/crossoverjie/cim/server/test/CommonTest.java b/cim-client/src/test/com/crossoverjie/cim/server/test/CommonTest.java
deleted file mode 100644
index 207c7b3a..00000000
--- a/cim-client/src/test/com/crossoverjie/cim/server/test/CommonTest.java
+++ /dev/null
@@ -1,217 +0,0 @@
-package com.crossoverjie.cim.server.test;
-
-
-import com.alibaba.fastjson.JSON;
-import com.crossoverjie.cim.client.vo.res.CIMServerResVO;
-import com.crossoverjie.cim.client.vo.res.OnlineUsersResVO;
-import com.vdurmont.emoji.EmojiParser;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.Test;
-
-
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import java.time.LocalDate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 22/05/2018 18:44
- * @since JDK 1.8
- */
-@Slf4j
-public class CommonTest {
-
- @Test
- public void test() {
-
- String json = "{\"code\":\"9000\",\"message\":\"成功\",\"reqNo\":null,\"dataBody\":{\"ip\":\"127.0.0.1\",\"port\":8081}}" ;
-
- CIMServerResVO cimServerResVO = JSON.parseObject(json, CIMServerResVO.class);
-
- System.out.println(cimServerResVO.toString());
-
- String text = "nihaoaaa" ;
- String[] split = text.split(" ");
- System.out.println(split.length);
- }
-
- @Test
- public void onlineUser(){
- List onlineUsers = new ArrayList<>(64) ;
-
- OnlineUsersResVO.DataBodyBean bodyBean = new OnlineUsersResVO.DataBodyBean() ;
-
- bodyBean.setUserId(100L);
- bodyBean.setUserName("zhangsan");
- onlineUsers.add(bodyBean) ;
-
- bodyBean = new OnlineUsersResVO.DataBodyBean();
- bodyBean.setUserId(200L);
- bodyBean.setUserName("crossoverJie");
- onlineUsers.add(bodyBean) ;
-
- log.info("list={}",JSON.toJSONString(onlineUsers));
-
- log.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
-
- for (OnlineUsersResVO.DataBodyBean onlineUser : onlineUsers) {
-
- log.info("userId={}=====userName={}",onlineUser.getUserId(),onlineUser.getUserName());
- }
- log.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
- }
-
-
- @Test
- public void searchMsg(){
- StringBuilder sb = new StringBuilder() ;
- String allMsg = "于是在之前的基础上我完善了一些内容,先来看看这个项目的介绍吧:\n" +
- "\n" +
- "CIM(CROSS-IM) 一款面向开发者的 IM(即时通讯)系统;同时提供了一些组件帮助开发者构建一款属于自己可水平扩展的 IM 。\n" +
- "\n" +
- "借助 CIM 你可以实现以下需求:" ;
-
- String key = "IM" ;
-
- String[] split = allMsg.split("\n");
- for (String msg : split) {
- if (msg.trim().contains(key)){
- sb.append(msg).append("\n") ;
- }
- }
- int pos = 0;
-
- String result = sb.toString();
-
- int count = 1 ;
- int multiple = 2 ;
- while((pos = result.indexOf(key, pos)) >= 0) {
-
- log.info("{},{}",pos, pos + key.length());
-
- if (count == 1){
- sb.insert(pos,"**");
- }else {
- Double pow = Math.pow(multiple, count);
- sb.insert(pos +pow.intValue(),"**");
- }
-
- pos += key.length();
-
- if (count == 1){
- sb.insert(pos +2,"**");
- }else {
- Double pow = Math.pow(multiple, count);
- sb.insert((pos +2) + pow.intValue(),"**");
-
- }
-
-
- count ++ ;
- }
-
- System.out.println(sb);
- }
- @Test
- public void searchMsg2(){
- StringBuilder sb = new StringBuilder() ;
- String allMsg = "于是在之前的基础上我完善了一些内容,先来看看这个项目的介绍吧:\n" +
- "\n" +
- "CIM(CROSS-IM) 一款面向开发者的 IM(即时通讯)系统;同时提供了一些组件帮助开发者构建一款属于自己可水平扩展的 IM 。\n" +
- "\n" +
- "借助 CIM 你可以实现以下需求:" ;
-
- String key = "CIM" ;
-
- String[] split = allMsg.split("\n");
- for (String msg : split) {
- if (msg.trim().contains(key)){
- sb.append(msg).append("\n") ;
- }
- }
- int pos = 0;
-
- String result = sb.toString();
-
- int count = 1 ;
- int multiple = 2 ;
- while((pos = result.indexOf(key, pos)) >= 0) {
-
- log.info("{},{}",pos, pos + key.length());
-
- pos += key.length();
-
-
- count ++ ;
- }
-
- System.out.println(sb.toString());
- System.out.println(sb.toString().replace(key,"\033[31;4m" + key+"\033[0m"));
- }
-
- @Test
- public void log(){
- String msg = "hahahdsadsd" ;
- LocalDate today = LocalDate.now();
- int year = today.getYear();
- int month = today.getMonthValue();
- int day = today.getDayOfMonth();
-
- String dir = "/opt/logs/cim/zhangsan" + "/";
- String fileName = dir + year + month + day + ".log";
- log.info("fileName={}", fileName);
-
- Path file = Paths.get(fileName);
- boolean exists = Files.exists(Paths.get(dir), LinkOption.NOFOLLOW_LINKS);
- try {
- if (!exists) {
- Files.createDirectories(Paths.get(dir));
- }
-
- List lines = Arrays.asList(msg);
-
- Files.write(file, lines, Charset.forName("UTF-8"), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
- } catch (IOException e) {
- log.info("IOException", e);
- }
-
- }
-
- @Test
- public void emoji() throws Exception{
- String str = "An :grinning:awesome :smiley:string 😄with a few :wink:emojis!";
- String result = EmojiParser.parseToUnicode(str);
- System.out.println(result);
-
-
- result = EmojiParser.parseToAliases(str);
- System.out.println(result);
-//
-// Collection all = EmojiManager.getAll();
-// for (Emoji emoji : all) {
-// System.out.println(EmojiParser.parseToAliases(emoji.getUnicode()) + "--->" + emoji.getUnicode() );
-// }
-
- }
-
- @Test
- public void emoji2(){
- String emostring ="😂";
-
- String face_with_tears_of_joy = emostring.replaceAll("\uD83D\uDE02", "face with tears of joy");
- System.out.println(face_with_tears_of_joy);
-
- System.out.println("======" + face_with_tears_of_joy.replaceAll("face with tears of joy","\uD83D\uDE02"));
- }
-
-}
diff --git a/cim-client/src/test/com/crossoverjie/cim/server/test/RouteTest.java b/cim-client/src/test/com/crossoverjie/cim/server/test/RouteTest.java
deleted file mode 100644
index 51a97205..00000000
--- a/cim-client/src/test/com/crossoverjie/cim/server/test/RouteTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.crossoverjie.cim.server.test;
-
-import com.crossoverjie.cim.client.CIMClientApplication;
-import com.crossoverjie.cim.client.service.RouteRequest;
-import com.crossoverjie.cim.client.vo.req.LoginReqVO;
-import com.crossoverjie.cim.client.vo.res.CIMServerResVO;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2018/12/23 22:39
- * @since JDK 1.8
- */
-@SpringBootTest(classes = CIMClientApplication.class)
-@RunWith(SpringRunner.class)
-@Slf4j
-public class RouteTest {
-
- @Value("${cim.user.id}")
- private long userId;
-
- @Value("${cim.user.userName}")
- private String userName;
-
- @Autowired
- private RouteRequest routeRequest ;
-
- @Test
- public void test() throws Exception {
- LoginReqVO vo = new LoginReqVO(userId,userName) ;
- CIMServerResVO.ServerInfo cimServer = routeRequest.getCIMServer(vo);
- log.info("cimServer=[{}]",cimServer.toString());
- }
-}
diff --git a/cim-client/src/test/com/crossoverjie/cim/client/service/InnerCommandContextTest.java b/cim-client/src/test/java/com/crossoverjie/cim/client/service/InnerCommandContextTest.java
similarity index 66%
rename from cim-client/src/test/com/crossoverjie/cim/client/service/InnerCommandContextTest.java
rename to cim-client/src/test/java/com/crossoverjie/cim/client/service/InnerCommandContextTest.java
index f878fafa..6bfc1463 100644
--- a/cim-client/src/test/com/crossoverjie/cim/client/service/InnerCommandContextTest.java
+++ b/cim-client/src/test/java/com/crossoverjie/cim/client/service/InnerCommandContextTest.java
@@ -1,7 +1,16 @@
package com.crossoverjie.cim.client.service;
+import com.alibaba.fastjson.JSONObject;
import com.crossoverjie.cim.client.CIMClientApplication;
+import com.crossoverjie.cim.common.core.proxy.RpcProxyManager;
import com.crossoverjie.cim.common.enums.SystemCommandEnum;
+import com.crossoverjie.cim.common.res.BaseResponse;
+import com.crossoverjie.cim.route.api.RouteApi;
+import com.crossoverjie.cim.route.api.vo.req.LoginReqVO;
+import com.crossoverjie.cim.route.api.vo.res.CIMServerResVO;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import okhttp3.OkHttpClient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@@ -16,63 +25,65 @@ public class InnerCommandContextTest {
private InnerCommandContext context;
@Test
- public void execute() {
+ public void execute() throws Exception {
String msg = ":all";
InnerCommand execute = context.getInstance(msg);
execute.process(msg) ;
}
- @Test
- public void execute3() {
+// @Test
+ public void execute3() throws Exception {
+ // TODO: 2024/8/31 Integration test
String msg = SystemCommandEnum.ONLINE_USER.getCommandType();
InnerCommand execute = context.getInstance(msg);
execute.process(msg) ;
}
@Test
- public void execute4() {
+ public void execute4() throws Exception {
String msg = ":q 天气";
InnerCommand execute = context.getInstance(msg);
execute.process(msg) ;
}
@Test
- public void execute5() {
+ public void execute5() throws Exception {
String msg = ":q crossoverJie";
InnerCommand execute = context.getInstance(msg);
execute.process(msg) ;
}
@Test
- public void execute6() {
+ public void execute6() throws Exception {
String msg = SystemCommandEnum.AI.getCommandType();
InnerCommand execute = context.getInstance(msg);
execute.process(msg) ;
}
@Test
- public void execute7() {
+ public void execute7() throws Exception {
String msg = SystemCommandEnum.QAI.getCommandType();
InnerCommand execute = context.getInstance(msg);
execute.process(msg) ;
}
- @Test
- public void execute8() {
+// @Test
+ public void execute8() throws Exception {
+ // TODO: 2024/8/31 Integration test
String msg = ":pu cross";
InnerCommand execute = context.getInstance(msg);
execute.process(msg) ;
}
@Test
- public void execute9() {
+ public void execute9() throws Exception {
String msg = SystemCommandEnum.INFO.getCommandType();
InnerCommand execute = context.getInstance(msg);
execute.process(msg) ;
}
@Test
- public void execute10() {
+ public void execute10() throws Exception {
String msg = "dsds";
InnerCommand execute = context.getInstance(msg);
execute.process(msg) ;
@@ -81,7 +92,7 @@ public void execute10() {
// @Test
- public void quit() {
+ public void quit() throws Exception {
String msg = ":q!";
InnerCommand execute = context.getInstance(msg);
execute.process(msg) ;
diff --git a/cim-client/src/test/com/crossoverjie/cim/client/service/impl/AsyncMsgLoggerTest.java b/cim-client/src/test/java/com/crossoverjie/cim/client/service/impl/AsyncMsgLoggerTest.java
similarity index 100%
rename from cim-client/src/test/com/crossoverjie/cim/client/service/impl/AsyncMsgLoggerTest.java
rename to cim-client/src/test/java/com/crossoverjie/cim/client/service/impl/AsyncMsgLoggerTest.java
diff --git a/cim-client/src/test/java/com/crossoverjie/cim/server/test/CommonTest.java b/cim-client/src/test/java/com/crossoverjie/cim/server/test/CommonTest.java
new file mode 100644
index 00000000..7233389b
--- /dev/null
+++ b/cim-client/src/test/java/com/crossoverjie/cim/server/test/CommonTest.java
@@ -0,0 +1,222 @@
+package com.crossoverjie.cim.server.test;
+
+
+import com.crossoverjie.cim.common.core.proxy.RpcProxyManager;
+import com.crossoverjie.cim.common.pojo.CIMUserInfo;
+import com.crossoverjie.cim.common.res.BaseResponse;
+import com.crossoverjie.cim.route.api.RouteApi;
+import com.crossoverjie.cim.route.api.vo.req.LoginReqVO;
+import com.crossoverjie.cim.route.api.vo.req.P2PReqVO;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.vdurmont.emoji.EmojiParser;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.time.LocalDate;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.OkHttpClient;
+import org.junit.Test;
+
+/**
+ * Function:
+ *
+ * @author crossoverJie
+ * Date: 22/05/2018 18:44
+ * @since JDK 1.8
+ */
+@Slf4j
+public class CommonTest {
+
+
+
+
+ @Test
+ public void searchMsg2(){
+ StringBuilder sb = new StringBuilder() ;
+ String allMsg = "于是在之前的基础上我完善了一些内容,先来看看这个项目的介绍吧:\n" +
+ "\n" +
+ "CIM(CROSS-IM) 一款面向开发者的 IM(即时通讯)系统;同时提供了一些组件帮助开发者构建一款属于自己可水平扩展的 IM 。\n" +
+ "\n" +
+ "借助 CIM 你可以实现以下需求:" ;
+
+ String key = "CIM" ;
+
+ String[] split = allMsg.split("\n");
+ for (String msg : split) {
+ if (msg.trim().contains(key)){
+ sb.append(msg).append("\n") ;
+ }
+ }
+ int pos = 0;
+
+ String result = sb.toString();
+
+ int count = 1 ;
+ int multiple = 2 ;
+ while((pos = result.indexOf(key, pos)) >= 0) {
+
+ log.info("{},{}",pos, pos + key.length());
+
+ pos += key.length();
+
+
+ count ++ ;
+ }
+
+ System.out.println(sb.toString());
+ System.out.println(sb.toString().replace(key,"\033[31;4m" + key+"\033[0m"));
+ }
+
+ @Test
+ public void log(){
+ String msg = "hahahdsadsd" ;
+ LocalDate today = LocalDate.now();
+ int year = today.getYear();
+ int month = today.getMonthValue();
+ int day = today.getDayOfMonth();
+
+ String dir = "/opt/logs/cim/zhangsan" + "/";
+ String fileName = dir + year + month + day + ".log";
+ log.info("fileName={}", fileName);
+
+ Path file = Paths.get(fileName);
+ boolean exists = Files.exists(Paths.get(dir), LinkOption.NOFOLLOW_LINKS);
+ try {
+ if (!exists) {
+ Files.createDirectories(Paths.get(dir));
+ }
+
+ List lines = Arrays.asList(msg);
+
+ Files.write(file, lines, Charset.forName("UTF-8"), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
+ } catch (IOException e) {
+ log.info("IOException", e);
+ }
+
+ }
+
+ @Test
+ public void emoji() throws Exception{
+ String str = "An :grinning:awesome :smiley:string 😄with a few :wink:emojis!";
+ String result = EmojiParser.parseToUnicode(str);
+ System.out.println(result);
+
+
+ result = EmojiParser.parseToAliases(str);
+ System.out.println(result);
+//
+// Collection all = EmojiManager.getAll();
+// for (Emoji emoji : all) {
+// System.out.println(EmojiParser.parseToAliases(emoji.getUnicode()) + "--->" + emoji.getUnicode() );
+// }
+
+ }
+
+ @Test
+ public void emoji2(){
+ String emostring ="😂";
+
+ String face_with_tears_of_joy = emostring.replaceAll("\uD83D\uDE02", "face with tears of joy");
+ System.out.println(face_with_tears_of_joy);
+
+ System.out.println("======" + face_with_tears_of_joy.replaceAll("face with tears of joy","\uD83D\uDE02"));
+ }
+
+// @Test
+ public void deSerialize() throws Exception {
+ RouteApi routeApi = RpcProxyManager.create(RouteApi.class, "http://localhost:8083", new OkHttpClient());
+
+ BaseResponse login =
+ routeApi.login(new LoginReqVO(1725722966520L, "cj"));
+ System.out.println(login.getDataBody());
+
+ BaseResponse> setBaseResponse = routeApi.onlineUser();
+ log.info("setBaseResponse={}",setBaseResponse.getDataBody());
+ }
+
+ @Test
+ public void json() throws JsonProcessingException, ClassNotFoundException {
+ String json = "{\"code\":\"9000\",\"message\":\"成功\",\"reqNo\":null,\"dataBody\":{\"ip\":\"127.0.0.1\",\"cimServerPort\":11211,\"httpPort\":8081}}";
+
+ ObjectMapper objectMapper = new ObjectMapper();
+ Class> generic = null;
+ for (Method declaredMethod : RouteApi.class.getDeclaredMethods()) {
+ if (declaredMethod.getName().equals("login")){
+ Type returnType = declaredMethod.getGenericReturnType();
+
+ // check if the return type is a parameterized type
+ if (returnType instanceof ParameterizedType) {
+ ParameterizedType parameterizedType = (ParameterizedType) returnType;
+
+ Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
+
+ for (Type typeArgument : actualTypeArguments) {
+ System.out.println("generic: " + typeArgument.getTypeName());
+ generic = Class.forName(typeArgument.getTypeName());
+ break;
+ }
+ } else {
+ System.out.println("not a generic type");
+ }
+ }
+ }
+ BaseResponse response = objectMapper.readValue(json,
+ objectMapper.getTypeFactory().constructParametricType(BaseResponse.class, generic));
+ System.out.println(response.getDataBody().getIp());
+ }
+
+
+ private static class Gen{
+ private T t;
+ private R r;
+ }
+
+ interface TestInterface{
+ Gen login();
+ }
+
+
+ @Test
+ public void test1() throws JsonProcessingException {
+ String json = "{\"code\":\"200\",\"message\":\"Success\",\"reqNo\":null,\"dataBody\":[{\"userId\":\"123\",\"userName\":\"Alice\"}, {\"userId\":\"456\",\"userName\":\"Bob\"}]}";
+
+ ObjectMapper objectMapper = new ObjectMapper();
+
+ // 获取 BaseResponse> 的泛型参数
+ Type setType = getGenericTypeOfBaseResponse();
+
+ // 将泛型类型传递给 ObjectMapper 进行反序列化
+ BaseResponse> response = objectMapper.readValue(json,
+ objectMapper.getTypeFactory().constructParametricType(BaseResponse.class, objectMapper.getTypeFactory().constructType(setType)));
+
+ System.out.println("Response Code: " + response.getCode());
+ System.out.println("Online Users: ");
+ for (CIMUserInfo user : response.getDataBody()) {
+ System.out.println("User ID: " + user.getUserId() + ", User Name: " + user.getUserName());
+ }
+ }
+
+ // 通过反射获取 BaseResponse> 中的泛型类型
+ public static Type getGenericTypeOfBaseResponse() {
+ // 这里模拟你需要处理的 BaseResponse>
+ ParameterizedType baseResponseType = (ParameterizedType) new TypeReference>>() {}.getType();
+
+ // 获取 BaseResponse 的泛型参数,即 Set
+ Type[] actualTypeArguments = baseResponseType.getActualTypeArguments();
+
+ // 返回第一个泛型参数 (Set)
+ return actualTypeArguments[0];
+ }
+}
diff --git a/cim-client/src/test/com/crossoverjie/cim/server/test/EchoTest.java b/cim-client/src/test/java/com/crossoverjie/cim/server/test/EchoTest.java
similarity index 100%
rename from cim-client/src/test/com/crossoverjie/cim/server/test/EchoTest.java
rename to cim-client/src/test/java/com/crossoverjie/cim/server/test/EchoTest.java
diff --git a/cim-client/src/test/resources/application.yaml b/cim-client/src/test/resources/application.yaml
new file mode 100644
index 00000000..6ea8c51e
--- /dev/null
+++ b/cim-client/src/test/resources/application.yaml
@@ -0,0 +1,40 @@
+spring:
+ application:
+ name: cim-client
+ main:
+ # this will not be used to create real spring context, because don't need this context in test case.
+ web-application-type: none
+
+# web port
+server:
+ port: 8082
+
+logging:
+ level:
+ root: error
+
+# enable swagger
+springdoc:
+ swagger-ui:
+ enabled: true
+
+# log path
+cim:
+ msg:
+ logger:
+ path: /opt/logs/cim/
+ route:
+ url: http://localhost:8083 # route url suggested that this is Nginx address
+ user: # cim userId and userName
+ id: 1722343979085
+ userName: zhangsan
+ callback:
+ thread:
+ queue:
+ size: 1000
+ pool:
+ size: 2
+ heartbeat:
+ time: 60 # cim heartbeat time (seconds)
+ reconnect:
+ count: 3
\ No newline at end of file
diff --git a/cim-common/pom.xml b/cim-common/pom.xml
index e878860a..c83720ea 100644
--- a/cim-common/pom.xml
+++ b/cim-common/pom.xml
@@ -8,7 +8,7 @@
1.0.0-SNAPSHOT
4.0.0
- 1.0.1-SNAPSHOT
+ 1.0.0-SNAPSHOT
cim-common
@@ -42,11 +42,40 @@
guava
+
- com.github.sgroschupf
+ com.101tec
zkclient
+
+
+ org.apache.curator
+ curator-recipes
+
+
+
+ org.apache.zookeeper
+ zookeeper
+
+
+
+ junit
+ junit
+
+
+
+ org.junit.vintage
+ junit-vintage-engine
+ test
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
io.netty
netty-all
@@ -58,4 +87,34 @@
fastjson
+
+
+
+
+ kr.motd.maven
+ os-maven-plugin
+ 1.5.0.Final
+
+
+
+
+ org.xolstice.maven.plugins
+ protobuf-maven-plugin
+ 0.5.1
+
+ com.google.protobuf:protoc:${protobuf-java.version}:exe:${os.detected.classifier}
+ grpc-java
+ io.grpc:protoc-gen-grpc-java:1.19.0:exe:${os.detected.classifier}
+
+
+
+
+ compile
+ compile-custom
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/constant/Constants.java b/cim-common/src/main/java/com/crossoverjie/cim/common/constant/Constants.java
index e4191eda..f128b46c 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/constant/Constants.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/constant/Constants.java
@@ -21,25 +21,9 @@ public class Constants {
*/
public static final String COUNTER_CLIENT_PUSH_COUNT = "counter.client.push.count" ;
-
- /**
- * 自定义报文类型
- */
- public static class CommandType{
- /**
- * 登录
- */
- public static final int LOGIN = 1 ;
- /**
- * 业务消息
- */
- public static final int MSG = 2 ;
-
- /**
- * ping
- */
- public static final int PING = 3 ;
+ public static class MetaKey {
+ public static final String USER_ID = "userId" ;
+ public static final String USER_NAME = "userName" ;
}
-
}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/DynamicUrl.java b/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/DynamicUrl.java
new file mode 100644
index 00000000..22e5f768
--- /dev/null
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/DynamicUrl.java
@@ -0,0 +1,15 @@
+package com.crossoverjie.cim.common.core.proxy;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author crossoverJie
+ */
+@Target({ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DynamicUrl {
+ boolean useMethodEndpoint() default true;
+}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/ProxyManager.java b/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/ProxyManager.java
deleted file mode 100644
index 92726f5a..00000000
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/ProxyManager.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.crossoverjie.cim.common.core.proxy;
-
-import com.alibaba.fastjson.JSONObject;
-import com.crossoverjie.cim.common.exception.CIMException;
-import com.crossoverjie.cim.common.util.HttpClient;
-import okhttp3.OkHttpClient;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.net.URI;
-
-import static com.crossoverjie.cim.common.enums.StatusEnum.VALIDATION_FAIL;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2020-04-25 00:18
- * @since JDK 1.8
- */
-public final class ProxyManager {
-
-
- private Class clazz;
-
- private String url;
-
- private OkHttpClient okHttpClient;
-
- /**
- *
- * @param clazz Proxied interface
- * @param url server provider url
- * @param okHttpClient http client
- */
- public ProxyManager(Class clazz, String url, OkHttpClient okHttpClient) {
- this.clazz = clazz;
- this.url = url;
- this.okHttpClient = okHttpClient;
- }
-
- /**
- * Get proxy instance of api.
- * @return
- */
- public T getInstance() {
- return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{clazz}, new ProxyInvocation());
- }
-
-
- private class ProxyInvocation implements InvocationHandler {
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- JSONObject jsonObject = new JSONObject();
- String serverUrl = url + "/" + method.getName() ;
-
- URI serverUri = new URI(serverUrl);
- serverUrl = serverUri.normalize().toString();
-
- if (args != null && args.length > 1) {
- throw new CIMException(VALIDATION_FAIL);
- }
-
- if (method.getParameterTypes().length > 0){
- Object para = args[0];
- Class> parameterType = method.getParameterTypes()[0];
- for (Field field : parameterType.getDeclaredFields()) {
- field.setAccessible(true);
- jsonObject.put(field.getName(), field.get(para));
- }
- }
- return HttpClient.call(okHttpClient, jsonObject.toString(), serverUrl);
- }
- }
-}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/Request.java b/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/Request.java
new file mode 100644
index 00000000..e5d797e8
--- /dev/null
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/Request.java
@@ -0,0 +1,16 @@
+package com.crossoverjie.cim.common.core.proxy;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * @author crossoverJie
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Request {
+ String method() default POST;
+ String url() default "";
+
+ String GET = "GET";
+ String POST = "POST";
+}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/RpcProxyManager.java b/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/RpcProxyManager.java
new file mode 100644
index 00000000..ce9323a8
--- /dev/null
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/core/proxy/RpcProxyManager.java
@@ -0,0 +1,229 @@
+package com.crossoverjie.cim.common.core.proxy;
+
+import static com.crossoverjie.cim.common.enums.StatusEnum.VALIDATION_FAIL;
+import com.alibaba.fastjson.JSONObject;
+import com.crossoverjie.cim.common.exception.CIMException;
+import com.crossoverjie.cim.common.util.HttpClient;
+import com.crossoverjie.cim.common.util.StringUtil;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.net.URI;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.OkHttpClient;
+import okhttp3.Response;
+
+/**
+ * RpcProxyManager is a proxy manager for creating dynamic proxy instances of interfaces.
+ * It handles HTTP requests and responses using OkHttpClient.
+ *
+ * @param the type of the proxied interface
+ */
+@Slf4j
+public final class RpcProxyManager {
+
+ private Class clazz;
+ private String url;
+ private OkHttpClient okHttpClient;
+ private final ObjectMapper objectMapper = new ObjectMapper();
+
+ /**
+ * Private constructor to initialize RpcProxyManager.
+ *
+ * @param clazz Proxied interface
+ * @param url Server provider URL
+ * @param okHttpClient HTTP client
+ */
+ private RpcProxyManager(Class clazz, String url, OkHttpClient okHttpClient) {
+ this.clazz = clazz;
+ this.url = url;
+ this.okHttpClient = okHttpClient;
+ }
+
+ private RpcProxyManager(Class clazz, OkHttpClient okHttpClient) {
+ this(clazz, "", okHttpClient);
+ }
+
+ /**
+ * Default private constructor.
+ */
+ private RpcProxyManager() {
+ }
+
+ /**
+ * Creates a proxy instance of the specified interface.
+ *
+ * @param clazz Proxied interface
+ * @param url Server provider URL
+ * @param okHttpClient HTTP client
+ * @param Type of the proxied interface
+ * @return Proxy instance of the specified interface
+ */
+ public static T create(Class clazz, String url, OkHttpClient okHttpClient) {
+ return new RpcProxyManager<>(clazz, url, okHttpClient).getInstance();
+ }
+
+ public static T create(Class clazz, OkHttpClient okHttpClient) {
+ return new RpcProxyManager<>(clazz, okHttpClient).getInstance();
+ }
+
+ /**
+ * Gets the proxy instance of the API.
+ *
+ * @return Proxy instance of the API
+ */
+ @SuppressWarnings("unchecked")
+ public T getInstance() {
+ return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{clazz},
+ new ProxyInvocation());
+ }
+
+ /**
+ * ProxyInvocation is an invocation handler for handling method calls on proxy instances.
+ */
+ private class ProxyInvocation implements InvocationHandler {
+
+ /**
+ * Handles method calls on proxy instances.
+ *
+ * @param proxy The proxy instance
+ * @param method The method being called
+ * @param args The arguments of the method call
+ * @return The result of the method call
+ * @throws Throwable if an error occurs during method invocation
+ */
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+
+ Response result = null;
+ String serverUrl = url + "/" + method.getName();
+ Request annotation = method.getAnnotation(Request.class);
+ if (annotation != null && StringUtil.isNotEmpty(annotation.url())) {
+ serverUrl = url + "/" + annotation.url();
+ }
+ URI serverUri = new URI(serverUrl);
+ serverUrl = serverUri.normalize().toString();
+
+ Object para = null;
+ Class> parameterType = null;
+ for (int i = 0; i < method.getParameterAnnotations().length; i++) {
+ Annotation[] annotations = method.getParameterAnnotations()[i];
+ if (annotations.length == 0) {
+ para = args[i];
+ parameterType = method.getParameterTypes()[i];
+ }
+
+ for (Annotation ann : annotations) {
+ if (ann instanceof DynamicUrl) {
+ if (args[i] instanceof String) {
+ serverUrl = (String) args[i];
+ if (((DynamicUrl) ann).useMethodEndpoint()) {
+ serverUrl = serverUrl + "/" + method.getName();
+ }
+ break;
+ } else {
+ throw new CIMException("DynamicUrl must be String type");
+ }
+ }
+ }
+ }
+
+ try {
+ if (annotation != null && annotation.method().equals(Request.GET)) {
+ result = HttpClient.get(okHttpClient, serverUrl);
+ } else {
+
+ if (args == null || args.length > 2 || para == null || parameterType == null) {
+ throw new IllegalArgumentException(VALIDATION_FAIL.message());
+ }
+ JSONObject jsonObject = new JSONObject();
+ for (Field field : parameterType.getDeclaredFields()) {
+ field.setAccessible(true);
+ jsonObject.put(field.getName(), field.get(para));
+ }
+
+ result = HttpClient.post(okHttpClient, jsonObject.toString(), serverUrl);
+ }
+ if (method.getReturnType() == void.class) {
+ return null;
+ }
+
+ String json = result.body().string();
+ Type genericTypeOfBaseResponse = getGenericTypeOfBaseResponse(method);
+ if (genericTypeOfBaseResponse == null) {
+ return objectMapper.readValue(json, method.getReturnType());
+ } else {
+ return objectMapper.readValue(json, objectMapper.getTypeFactory()
+ .constructParametricType(method.getReturnType(),
+ objectMapper.getTypeFactory().constructType(genericTypeOfBaseResponse)));
+ }
+ } finally {
+ if (result != null) {
+ result.body().close();
+ }
+ }
+ }
+ }
+
+ private Type getGenericTypeOfBaseResponse(Method declaredMethod) {
+ Type returnType = declaredMethod.getGenericReturnType();
+
+ // check if the return type is a parameterized type
+ if (returnType instanceof ParameterizedType parameterizedType) {
+
+ Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
+
+ for (Type typeArgument : actualTypeArguments) {
+ return typeArgument;
+ }
+ }
+
+ return null;
+
+ }
+
+ /**
+ * Gets the generic type of the BaseResponse.
+ *
+ * @param declaredMethod The method whose return type is being checked
+ * @return The generic type of the BaseResponse, or null if not found
+ * @throws ClassNotFoundException if the class of the generic type is not found
+ private Class> getBaseResponseGeneric(Method declaredMethod) throws ClassNotFoundException {
+
+ Type returnType = declaredMethod.getGenericReturnType();
+
+ // check if the return type is a parameterized type
+ if (returnType instanceof ParameterizedType parameterizedType) {
+
+ Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
+
+ for (Type typeArgument : actualTypeArguments) {
+ // BaseResponse only has one generic type
+ return getClass(typeArgument);
+ }
+ }
+
+ return null;
+ }
+
+ public static Class> getClass(Type type) throws ClassNotFoundException {
+ if (type instanceof Class>) {
+ // 普通类型,直接返回
+ return (Class>) type;
+ } else if (type instanceof ParameterizedType) {
+ // 参数化类型,返回原始类型
+ return getClass(((ParameterizedType) type).getRawType());
+ } else if (type instanceof TypeVariable>) {
+ // 类型变量,无法在运行时获取具体类型
+ return Object.class;
+ } else {
+ throw new ClassNotFoundException("无法处理的类型: " + type.toString());
+ }
+ }*/
+
+}
\ No newline at end of file
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/data/construct/SortArrayMap.java b/cim-common/src/main/java/com/crossoverjie/cim/common/data/construct/SortArrayMap.java
index e296d8b5..5e5e48a7 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/data/construct/SortArrayMap.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/data/construct/SortArrayMap.java
@@ -1,7 +1,13 @@
package com.crossoverjie.cim.common.data.construct;
+import java.util.AbstractMap;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import org.apache.curator.shaded.com.google.common.collect.Sets;
/**
* Function:根据 key 排序的 Map
@@ -10,7 +16,7 @@
* Date: 2019-02-25 18:17
* @since JDK 1.8
*/
-public class SortArrayMap {
+public class SortArrayMap extends AbstractMap {
/**
* 核心数组
@@ -39,6 +45,13 @@ public void add(Long key, String value) {
buckets[size++] = node;
}
+ public SortArrayMap remove(String value){
+ List list = new ArrayList<>(Arrays.asList(buckets));
+ list.removeIf(next -> next != null && next.value.equals(value));
+ buckets = list.toArray(new Node[0]);
+ return this;
+ }
+
/**
* 校验是否需要扩容
* @param size
@@ -78,14 +91,11 @@ public String firstNodeValue(long key) {
* 排序
*/
public void sort() {
- Arrays.sort(buckets, 0, size, new Comparator() {
- @Override
- public int compare(Node o1, Node o2) {
- if (o1.key > o2.key) {
- return 1;
- } else {
- return -1;
- }
+ Arrays.sort(buckets, 0, size, (o1, o2) -> {
+ if (o1.key > o2.key) {
+ return 1;
+ } else {
+ return 0;
}
});
}
@@ -108,6 +118,27 @@ public void clear(){
size = 0 ;
}
+ @Override
+ public Set> entrySet() {
+ Set> set = Sets.newHashSet();
+ for (Node bucket : buckets) {
+ set.add(new SimpleEntry<>(String.valueOf(bucket.key), bucket.value));
+ }
+ return set;
+ }
+
+ @Override
+ public Set keySet() {
+ Set set = Sets.newHashSet();
+ for (Node bucket : buckets) {
+ if (bucket == null){
+ continue;
+ }
+ set.add(bucket.value);
+ }
+ return set;
+ }
+
/**
* 数据节点
*/
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/enums/StatusEnum.java b/cim-common/src/main/java/com/crossoverjie/cim/common/enums/StatusEnum.java
index d19afbd7..9f93622f 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/enums/StatusEnum.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/enums/StatusEnum.java
@@ -10,7 +10,7 @@
public enum StatusEnum {
/** 成功 */
- SUCCESS("9000", "成功"),
+ SUCCESS("9000", "Success"),
/** 成功 */
FALLBACK("8000", "FALL_BACK"),
/** 参数校验失败**/
@@ -25,7 +25,7 @@ public enum StatusEnum {
REQUEST_LIMIT("6000", "请求限流"),
/** 账号不在线 */
- OFF_LINE("7000", "你选择的账号不在线,请重新选择!"),
+ OFF_LINE("7000", "You selected user is offline!, please try again later!"),
SERVER_NOT_AVAILABLE("7100", "cim server is not available, please try again later!"),
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/metastore/AbstractConfiguration.java b/cim-common/src/main/java/com/crossoverjie/cim/common/metastore/AbstractConfiguration.java
new file mode 100644
index 00000000..e028ea26
--- /dev/null
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/metastore/AbstractConfiguration.java
@@ -0,0 +1,16 @@
+package com.crossoverjie.cim.common.metastore;
+
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * @author crossverJie
+ */
+@Data
+@Builder
+public class AbstractConfiguration {
+
+ private String metaServiceUri;
+ private int timeoutMs;
+ private RETRY retryPolicy;
+}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/metastore/MetaStore.java b/cim-common/src/main/java/com/crossoverjie/cim/common/metastore/MetaStore.java
new file mode 100644
index 00000000..b2a09a94
--- /dev/null
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/metastore/MetaStore.java
@@ -0,0 +1,49 @@
+package com.crossoverjie.cim.common.metastore;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * @author crossoverJie
+ */
+public interface MetaStore {
+
+ void initialize(AbstractConfiguration> configuration) throws Exception;
+
+ /**
+ * Get available server list
+ * @return available server list
+ * @throws Exception exception
+ */
+ Set getAvailableServerList() throws Exception;
+
+ /**
+ * Add server to meta store
+ * @throws Exception exception
+ */
+ void addServer(String ip, int cimServerPort, int httpPort) throws Exception;
+
+ /**
+ * Subscribe server list
+ * @param childListener child listener
+ * @throws Exception exception
+ */
+ void listenServerList(ChildListener childListener) throws Exception;
+
+
+ /**
+ * @throws Exception
+ */
+ void rebuildCache() throws Exception;
+
+ interface ChildListener {
+ /**
+ * Child changed
+ * @param parentPath parent path(eg. for zookeeper: [/cim])
+ * @param currentChildren current children
+ * @throws Exception exception
+ */
+ void childChanged(String parentPath, List currentChildren) throws Exception;
+ }
+}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/metastore/ZkConfiguration.java b/cim-common/src/main/java/com/crossoverjie/cim/common/metastore/ZkConfiguration.java
new file mode 100644
index 00000000..4b95ee72
--- /dev/null
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/metastore/ZkConfiguration.java
@@ -0,0 +1,12 @@
+package com.crossoverjie.cim.common.metastore;
+
+import org.apache.curator.RetryPolicy;
+
+/**
+ * @author crossoverJie
+ */
+public class ZkConfiguration extends AbstractConfiguration {
+ ZkConfiguration(String metaServiceUri, int timeout, RetryPolicy retryPolicy) {
+ super(metaServiceUri, timeout, retryPolicy);
+ }
+}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/metastore/ZkMetaStoreImpl.java b/cim-common/src/main/java/com/crossoverjie/cim/common/metastore/ZkMetaStoreImpl.java
new file mode 100644
index 00000000..91f141f9
--- /dev/null
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/metastore/ZkMetaStoreImpl.java
@@ -0,0 +1,119 @@
+package com.crossoverjie.cim.common.metastore;
+
+import com.crossoverjie.cim.common.pojo.RouteInfo;
+import com.crossoverjie.cim.common.util.RouteInfoParseUtil;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import lombok.extern.slf4j.Slf4j;
+import org.I0Itec.zkclient.ZkClient;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.Watcher;
+
+/**
+ * @author crossovreJie
+ */
+@Slf4j
+public class ZkMetaStoreImpl implements MetaStore {
+ public static final String ROOT = "/cim";
+
+ private ZkClient client;
+
+ LoadingCache cache;
+
+ @Override
+ public void initialize(AbstractConfiguration> configuration) throws Exception {
+ // TODO: 2024/8/19 Change to set or caffeine?
+ cache = CacheBuilder.newBuilder()
+ .concurrencyLevel(3)
+ .build(new CacheLoader<>() {
+ @Override
+ public String load(String s) {
+ return null;
+ }
+ });
+ client = new ZkClient(configuration.getMetaServiceUri(), configuration.getTimeoutMs());
+ }
+
+ @Override
+ public Set getAvailableServerList() throws Exception {
+ if (cache.size() > 0) {
+ return cache.asMap().keySet();
+ }
+ List coll = client.getChildren(ROOT);
+ Map voidMap = coll.stream().collect(Collectors.toMap(
+ Function.identity(),
+ Function.identity()
+ ));
+ cache.putAll(voidMap);
+ return voidMap.keySet();
+ }
+
+ @Override
+ public void addServer(String ip, int cimServerPort, int httpPort) throws Exception {
+ boolean exists = client.exists(ROOT);
+ if (!exists) {
+ client.createPersistent(ROOT);
+ }
+ String zkParse = RouteInfoParseUtil.parse(RouteInfo.builder()
+ .ip(ip)
+ .cimServerPort(cimServerPort)
+ .httpPort(httpPort)
+ .build());
+ String serverPath = String.format("%s/%s", ROOT, zkParse);
+ client.createEphemeral(serverPath);
+ log.info("Add server to zk [{}]", serverPath);
+ }
+
+ @Override
+ public void listenServerList(ChildListener childListener) throws Exception {
+ client.subscribeChildChanges(ROOT, (parentPath, currentChildren) -> {
+ log.info("Clear and update local cache parentPath=[{}],current server list=[{}]", parentPath, currentChildren.toString());
+ childListener.childChanged(parentPath, currentChildren);
+
+ // TODO: 2024/8/19 maybe can reuse currentChildren.
+ // Because rebuildCache() will re-fetch the server list from zk.
+ rebuildCache();
+ });
+ }
+
+ @Override
+ public synchronized void rebuildCache() throws Exception {
+ cache.invalidateAll();
+
+ // Because of calling invalidateAll, this method will re-fetch the server list from zk.
+ this.getAvailableServerList();
+
+ }
+
+
+ private List watchedGetChildren(CuratorFramework client, String path) throws Exception {
+ /**
+ * Get children and set a watcher on the node. The watcher notification will come through the
+ * CuratorListener (see setDataAsync() above).
+ */
+ return client.getChildren().watched().forPath(path);
+ }
+
+ private void createEphemeral(CuratorFramework client, String path, byte[] payload) throws Exception {
+ // this will create the given EPHEMERAL ZNode with the given data
+ client.create().withMode(CreateMode.EPHEMERAL).forPath(path, payload);
+ }
+
+ private void create(CuratorFramework client, String path, byte[] payload) throws Exception {
+ // this will create the given ZNode with the given data
+ client.create().forPath(path, payload);
+ }
+
+ private void watchedGetChildren(CuratorFramework client, String path, Watcher watcher)
+ throws Exception {
+ // Get children and set the given watcher on the node.
+ client.getChildren().usingWatcher(watcher).forPath(path);
+ }
+}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/pojo/CIMUserInfo.java b/cim-common/src/main/java/com/crossoverjie/cim/common/pojo/CIMUserInfo.java
index 2e50f3fa..5c6ed5b7 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/pojo/CIMUserInfo.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/pojo/CIMUserInfo.java
@@ -1,5 +1,9 @@
package com.crossoverjie.cim.common.pojo;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
/**
* Function: 用户信息
*
@@ -7,36 +11,11 @@
* Date: 2018/12/24 02:33
* @since JDK 1.8
*/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
public class CIMUserInfo {
private Long userId ;
private String userName ;
- public CIMUserInfo(Long userId, String userName) {
- this.userId = userId;
- this.userName = userName;
- }
-
- public Long getUserId() {
- return userId;
- }
-
- public void setUserId(Long userId) {
- this.userId = userId;
- }
-
- public String getUserName() {
- return userName;
- }
-
- public void setUserName(String userName) {
- this.userName = userName;
- }
-
- @Override
- public String toString() {
- return "CIMUserInfo{" +
- "userId=" + userId +
- ", userName='" + userName + '\'' +
- '}';
- }
}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/pojo/RouteInfo.java b/cim-common/src/main/java/com/crossoverjie/cim/common/pojo/RouteInfo.java
index eec73743..0e72592f 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/pojo/RouteInfo.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/pojo/RouteInfo.java
@@ -1,5 +1,9 @@
package com.crossoverjie.cim.common.pojo;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
/**
* Function:
*
@@ -7,39 +11,12 @@
* Date: 2020-04-12 20:48
* @since JDK 1.8
*/
+@Data
+@AllArgsConstructor
+@Builder
public final class RouteInfo {
private String ip ;
private Integer cimServerPort;
private Integer httpPort;
-
- public RouteInfo(String ip, Integer cimServerPort, Integer httpPort) {
- this.ip = ip;
- this.cimServerPort = cimServerPort;
- this.httpPort = httpPort;
- }
-
- public String getIp() {
- return ip;
- }
-
- public void setIp(String ip) {
- this.ip = ip;
- }
-
- public Integer getCimServerPort() {
- return cimServerPort;
- }
-
- public void setCimServerPort(Integer cimServerPort) {
- this.cimServerPort = cimServerPort;
- }
-
- public Integer getHttpPort() {
- return httpPort;
- }
-
- public void setHttpPort(Integer httpPort) {
- this.httpPort = httpPort;
- }
}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/protocol/CIMRequestProto.java b/cim-common/src/main/java/com/crossoverjie/cim/common/protocol/CIMRequestProto.java
deleted file mode 100644
index 2b61c77a..00000000
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/protocol/CIMRequestProto.java
+++ /dev/null
@@ -1,811 +0,0 @@
-// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: BaseRequestProto.proto
-
-package com.crossoverjie.cim.common.protocol;
-
-public final class CIMRequestProto {
- private CIMRequestProto() {}
- public static void registerAllExtensions(
- com.google.protobuf.ExtensionRegistryLite registry) {
- }
-
- public static void registerAllExtensions(
- com.google.protobuf.ExtensionRegistry registry) {
- registerAllExtensions(
- (com.google.protobuf.ExtensionRegistryLite) registry);
- }
- public interface CIMReqProtocolOrBuilder extends
- // @@protoc_insertion_point(interface_extends:protocol.CIMReqProtocol)
- com.google.protobuf.MessageOrBuilder {
-
- /**
- * required int64 requestId = 2;
- */
- boolean hasRequestId();
- /**
- * required int64 requestId = 2;
- */
- long getRequestId();
-
- /**
- * required string reqMsg = 1;
- */
- boolean hasReqMsg();
- /**
- * required string reqMsg = 1;
- */
- String getReqMsg();
- /**
- * required string reqMsg = 1;
- */
- com.google.protobuf.ByteString
- getReqMsgBytes();
-
- /**
- * required int32 type = 3;
- */
- boolean hasType();
- /**
- * required int32 type = 3;
- */
- int getType();
- }
- /**
- * Protobuf type {@code protocol.CIMReqProtocol}
- */
- public static final class CIMReqProtocol extends
- com.google.protobuf.GeneratedMessageV3 implements
- // @@protoc_insertion_point(message_implements:protocol.CIMReqProtocol)
- CIMReqProtocolOrBuilder {
- private static final long serialVersionUID = 0L;
- // Use CIMReqProtocol.newBuilder() to construct.
- private CIMReqProtocol(com.google.protobuf.GeneratedMessageV3.Builder> builder) {
- super(builder);
- }
- private CIMReqProtocol() {
- requestId_ = 0L;
- reqMsg_ = "";
- type_ = 0;
- }
-
- @Override
- public final com.google.protobuf.UnknownFieldSet
- getUnknownFields() {
- return this.unknownFields;
- }
- private CIMReqProtocol(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- this();
- if (extensionRegistry == null) {
- throw new NullPointerException();
- }
- int mutable_bitField0_ = 0;
- com.google.protobuf.UnknownFieldSet.Builder unknownFields =
- com.google.protobuf.UnknownFieldSet.newBuilder();
- try {
- boolean done = false;
- while (!done) {
- int tag = input.readTag();
- switch (tag) {
- case 0:
- done = true;
- break;
- default: {
- if (!parseUnknownField(
- input, unknownFields, extensionRegistry, tag)) {
- done = true;
- }
- break;
- }
- case 10: {
- com.google.protobuf.ByteString bs = input.readBytes();
- bitField0_ |= 0x00000002;
- reqMsg_ = bs;
- break;
- }
- case 16: {
- bitField0_ |= 0x00000001;
- requestId_ = input.readInt64();
- break;
- }
- case 24: {
- bitField0_ |= 0x00000004;
- type_ = input.readInt32();
- break;
- }
- }
- }
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- throw e.setUnfinishedMessage(this);
- } catch (java.io.IOException e) {
- throw new com.google.protobuf.InvalidProtocolBufferException(
- e).setUnfinishedMessage(this);
- } finally {
- this.unknownFields = unknownFields.build();
- makeExtensionsImmutable();
- }
- }
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return CIMRequestProto.internal_static_protocol_CIMReqProtocol_descriptor;
- }
-
- protected FieldAccessorTable
- internalGetFieldAccessorTable() {
- return CIMRequestProto.internal_static_protocol_CIMReqProtocol_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- CIMReqProtocol.class, Builder.class);
- }
-
- private int bitField0_;
- public static final int REQUESTID_FIELD_NUMBER = 2;
- private long requestId_;
- /**
- * required int64 requestId = 2;
- */
- public boolean hasRequestId() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * required int64 requestId = 2;
- */
- public long getRequestId() {
- return requestId_;
- }
-
- public static final int REQMSG_FIELD_NUMBER = 1;
- private volatile Object reqMsg_;
- /**
- * required string reqMsg = 1;
- */
- public boolean hasReqMsg() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * required string reqMsg = 1;
- */
- public String getReqMsg() {
- Object ref = reqMsg_;
- if (ref instanceof String) {
- return (String) ref;
- } else {
- com.google.protobuf.ByteString bs =
- (com.google.protobuf.ByteString) ref;
- String s = bs.toStringUtf8();
- if (bs.isValidUtf8()) {
- reqMsg_ = s;
- }
- return s;
- }
- }
- /**
- * required string reqMsg = 1;
- */
- public com.google.protobuf.ByteString
- getReqMsgBytes() {
- Object ref = reqMsg_;
- if (ref instanceof String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (String) ref);
- reqMsg_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
-
- public static final int TYPE_FIELD_NUMBER = 3;
- private int type_;
- /**
- * required int32 type = 3;
- */
- public boolean hasType() {
- return ((bitField0_ & 0x00000004) == 0x00000004);
- }
- /**
- * required int32 type = 3;
- */
- public int getType() {
- return type_;
- }
-
- private byte memoizedIsInitialized = -1;
- public final boolean isInitialized() {
- byte isInitialized = memoizedIsInitialized;
- if (isInitialized == 1) return true;
- if (isInitialized == 0) return false;
-
- if (!hasRequestId()) {
- memoizedIsInitialized = 0;
- return false;
- }
- if (!hasReqMsg()) {
- memoizedIsInitialized = 0;
- return false;
- }
- if (!hasType()) {
- memoizedIsInitialized = 0;
- return false;
- }
- memoizedIsInitialized = 1;
- return true;
- }
-
- public void writeTo(com.google.protobuf.CodedOutputStream output)
- throws java.io.IOException {
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- com.google.protobuf.GeneratedMessageV3.writeString(output, 1, reqMsg_);
- }
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- output.writeInt64(2, requestId_);
- }
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
- output.writeInt32(3, type_);
- }
- unknownFields.writeTo(output);
- }
-
- public int getSerializedSize() {
- int size = memoizedSize;
- if (size != -1) return size;
-
- size = 0;
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, reqMsg_);
- }
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- size += com.google.protobuf.CodedOutputStream
- .computeInt64Size(2, requestId_);
- }
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
- size += com.google.protobuf.CodedOutputStream
- .computeInt32Size(3, type_);
- }
- size += unknownFields.getSerializedSize();
- memoizedSize = size;
- return size;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (obj == this) {
- return true;
- }
- if (!(obj instanceof CIMReqProtocol)) {
- return super.equals(obj);
- }
- CIMReqProtocol other = (CIMReqProtocol) obj;
-
- boolean result = true;
- result = result && (hasRequestId() == other.hasRequestId());
- if (hasRequestId()) {
- result = result && (getRequestId()
- == other.getRequestId());
- }
- result = result && (hasReqMsg() == other.hasReqMsg());
- if (hasReqMsg()) {
- result = result && getReqMsg()
- .equals(other.getReqMsg());
- }
- result = result && (hasType() == other.hasType());
- if (hasType()) {
- result = result && (getType()
- == other.getType());
- }
- result = result && unknownFields.equals(other.unknownFields);
- return result;
- }
-
- @Override
- public int hashCode() {
- if (memoizedHashCode != 0) {
- return memoizedHashCode;
- }
- int hash = 41;
- hash = (19 * hash) + getDescriptor().hashCode();
- if (hasRequestId()) {
- hash = (37 * hash) + REQUESTID_FIELD_NUMBER;
- hash = (53 * hash) + com.google.protobuf.Internal.hashLong(
- getRequestId());
- }
- if (hasReqMsg()) {
- hash = (37 * hash) + REQMSG_FIELD_NUMBER;
- hash = (53 * hash) + getReqMsg().hashCode();
- }
- if (hasType()) {
- hash = (37 * hash) + TYPE_FIELD_NUMBER;
- hash = (53 * hash) + getType();
- }
- hash = (29 * hash) + unknownFields.hashCode();
- memoizedHashCode = hash;
- return hash;
- }
-
- public static CIMReqProtocol parseFrom(
- java.nio.ByteBuffer data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static CIMReqProtocol parseFrom(
- java.nio.ByteBuffer data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static CIMReqProtocol parseFrom(
- com.google.protobuf.ByteString data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static CIMReqProtocol parseFrom(
- com.google.protobuf.ByteString data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static CIMReqProtocol parseFrom(byte[] data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static CIMReqProtocol parseFrom(
- byte[] data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static CIMReqProtocol parseFrom(java.io.InputStream input)
- throws java.io.IOException {
- return com.google.protobuf.GeneratedMessageV3
- .parseWithIOException(PARSER, input);
- }
- public static CIMReqProtocol parseFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return com.google.protobuf.GeneratedMessageV3
- .parseWithIOException(PARSER, input, extensionRegistry);
- }
- public static CIMReqProtocol parseDelimitedFrom(java.io.InputStream input)
- throws java.io.IOException {
- return com.google.protobuf.GeneratedMessageV3
- .parseDelimitedWithIOException(PARSER, input);
- }
- public static CIMReqProtocol parseDelimitedFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return com.google.protobuf.GeneratedMessageV3
- .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
- }
- public static CIMReqProtocol parseFrom(
- com.google.protobuf.CodedInputStream input)
- throws java.io.IOException {
- return com.google.protobuf.GeneratedMessageV3
- .parseWithIOException(PARSER, input);
- }
- public static CIMReqProtocol parseFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return com.google.protobuf.GeneratedMessageV3
- .parseWithIOException(PARSER, input, extensionRegistry);
- }
-
- public Builder newBuilderForType() { return newBuilder(); }
- public static Builder newBuilder() {
- return DEFAULT_INSTANCE.toBuilder();
- }
- public static Builder newBuilder(CIMReqProtocol prototype) {
- return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
- }
- public Builder toBuilder() {
- return this == DEFAULT_INSTANCE
- ? new Builder() : new Builder().mergeFrom(this);
- }
-
- @Override
- protected Builder newBuilderForType(
- BuilderParent parent) {
- Builder builder = new Builder(parent);
- return builder;
- }
- /**
- * Protobuf type {@code protocol.CIMReqProtocol}
- */
- public static final class Builder extends
- com.google.protobuf.GeneratedMessageV3.Builder implements
- // @@protoc_insertion_point(builder_implements:protocol.CIMReqProtocol)
- CIMReqProtocolOrBuilder {
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return CIMRequestProto.internal_static_protocol_CIMReqProtocol_descriptor;
- }
-
- protected FieldAccessorTable
- internalGetFieldAccessorTable() {
- return CIMRequestProto.internal_static_protocol_CIMReqProtocol_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- CIMReqProtocol.class, Builder.class);
- }
-
- // Construct using com.crossoverjie.cim.common.protocol.CIMRequestProto.CIMReqProtocol.newBuilder()
- private Builder() {
- maybeForceBuilderInitialization();
- }
-
- private Builder(
- BuilderParent parent) {
- super(parent);
- maybeForceBuilderInitialization();
- }
- private void maybeForceBuilderInitialization() {
- if (com.google.protobuf.GeneratedMessageV3
- .alwaysUseFieldBuilders) {
- }
- }
- public Builder clear() {
- super.clear();
- requestId_ = 0L;
- bitField0_ = (bitField0_ & ~0x00000001);
- reqMsg_ = "";
- bitField0_ = (bitField0_ & ~0x00000002);
- type_ = 0;
- bitField0_ = (bitField0_ & ~0x00000004);
- return this;
- }
-
- public com.google.protobuf.Descriptors.Descriptor
- getDescriptorForType() {
- return CIMRequestProto.internal_static_protocol_CIMReqProtocol_descriptor;
- }
-
- public CIMReqProtocol getDefaultInstanceForType() {
- return CIMReqProtocol.getDefaultInstance();
- }
-
- public CIMReqProtocol build() {
- CIMReqProtocol result = buildPartial();
- if (!result.isInitialized()) {
- throw newUninitializedMessageException(result);
- }
- return result;
- }
-
- public CIMReqProtocol buildPartial() {
- CIMReqProtocol result = new CIMReqProtocol(this);
- int from_bitField0_ = bitField0_;
- int to_bitField0_ = 0;
- if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
- to_bitField0_ |= 0x00000001;
- }
- result.requestId_ = requestId_;
- if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
- to_bitField0_ |= 0x00000002;
- }
- result.reqMsg_ = reqMsg_;
- if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
- to_bitField0_ |= 0x00000004;
- }
- result.type_ = type_;
- result.bitField0_ = to_bitField0_;
- onBuilt();
- return result;
- }
-
- public Builder clone() {
- return (Builder) super.clone();
- }
- public Builder setField(
- com.google.protobuf.Descriptors.FieldDescriptor field,
- Object value) {
- return (Builder) super.setField(field, value);
- }
- public Builder clearField(
- com.google.protobuf.Descriptors.FieldDescriptor field) {
- return (Builder) super.clearField(field);
- }
- public Builder clearOneof(
- com.google.protobuf.Descriptors.OneofDescriptor oneof) {
- return (Builder) super.clearOneof(oneof);
- }
- public Builder setRepeatedField(
- com.google.protobuf.Descriptors.FieldDescriptor field,
- int index, Object value) {
- return (Builder) super.setRepeatedField(field, index, value);
- }
- public Builder addRepeatedField(
- com.google.protobuf.Descriptors.FieldDescriptor field,
- Object value) {
- return (Builder) super.addRepeatedField(field, value);
- }
- public Builder mergeFrom(com.google.protobuf.Message other) {
- if (other instanceof CIMReqProtocol) {
- return mergeFrom((CIMReqProtocol)other);
- } else {
- super.mergeFrom(other);
- return this;
- }
- }
-
- public Builder mergeFrom(CIMReqProtocol other) {
- if (other == CIMReqProtocol.getDefaultInstance()) return this;
- if (other.hasRequestId()) {
- setRequestId(other.getRequestId());
- }
- if (other.hasReqMsg()) {
- bitField0_ |= 0x00000002;
- reqMsg_ = other.reqMsg_;
- onChanged();
- }
- if (other.hasType()) {
- setType(other.getType());
- }
- this.mergeUnknownFields(other.unknownFields);
- onChanged();
- return this;
- }
-
- public final boolean isInitialized() {
- if (!hasRequestId()) {
- return false;
- }
- if (!hasReqMsg()) {
- return false;
- }
- if (!hasType()) {
- return false;
- }
- return true;
- }
-
- public Builder mergeFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- CIMReqProtocol parsedMessage = null;
- try {
- parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- parsedMessage = (CIMReqProtocol) e.getUnfinishedMessage();
- throw e.unwrapIOException();
- } finally {
- if (parsedMessage != null) {
- mergeFrom(parsedMessage);
- }
- }
- return this;
- }
- private int bitField0_;
-
- private long requestId_ ;
- /**
- * required int64 requestId = 2;
- */
- public boolean hasRequestId() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * required int64 requestId = 2;
- */
- public long getRequestId() {
- return requestId_;
- }
- /**
- * required int64 requestId = 2;
- */
- public Builder setRequestId(long value) {
- bitField0_ |= 0x00000001;
- requestId_ = value;
- onChanged();
- return this;
- }
- /**
- * required int64 requestId = 2;
- */
- public Builder clearRequestId() {
- bitField0_ = (bitField0_ & ~0x00000001);
- requestId_ = 0L;
- onChanged();
- return this;
- }
-
- private Object reqMsg_ = "";
- /**
- * required string reqMsg = 1;
- */
- public boolean hasReqMsg() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * required string reqMsg = 1;
- */
- public String getReqMsg() {
- Object ref = reqMsg_;
- if (!(ref instanceof String)) {
- com.google.protobuf.ByteString bs =
- (com.google.protobuf.ByteString) ref;
- String s = bs.toStringUtf8();
- if (bs.isValidUtf8()) {
- reqMsg_ = s;
- }
- return s;
- } else {
- return (String) ref;
- }
- }
- /**
- * required string reqMsg = 1;
- */
- public com.google.protobuf.ByteString
- getReqMsgBytes() {
- Object ref = reqMsg_;
- if (ref instanceof String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (String) ref);
- reqMsg_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
- /**
- * required string reqMsg = 1;
- */
- public Builder setReqMsg(
- String value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000002;
- reqMsg_ = value;
- onChanged();
- return this;
- }
- /**
- * required string reqMsg = 1;
- */
- public Builder clearReqMsg() {
- bitField0_ = (bitField0_ & ~0x00000002);
- reqMsg_ = getDefaultInstance().getReqMsg();
- onChanged();
- return this;
- }
- /**
- * required string reqMsg = 1;
- */
- public Builder setReqMsgBytes(
- com.google.protobuf.ByteString value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000002;
- reqMsg_ = value;
- onChanged();
- return this;
- }
-
- private int type_ ;
- /**
- * required int32 type = 3;
- */
- public boolean hasType() {
- return ((bitField0_ & 0x00000004) == 0x00000004);
- }
- /**
- * required int32 type = 3;
- */
- public int getType() {
- return type_;
- }
- /**
- * required int32 type = 3;
- */
- public Builder setType(int value) {
- bitField0_ |= 0x00000004;
- type_ = value;
- onChanged();
- return this;
- }
- /**
- * required int32 type = 3;
- */
- public Builder clearType() {
- bitField0_ = (bitField0_ & ~0x00000004);
- type_ = 0;
- onChanged();
- return this;
- }
- public final Builder setUnknownFields(
- final com.google.protobuf.UnknownFieldSet unknownFields) {
- return super.setUnknownFields(unknownFields);
- }
-
- public final Builder mergeUnknownFields(
- final com.google.protobuf.UnknownFieldSet unknownFields) {
- return super.mergeUnknownFields(unknownFields);
- }
-
-
- // @@protoc_insertion_point(builder_scope:protocol.CIMReqProtocol)
- }
-
- // @@protoc_insertion_point(class_scope:protocol.CIMReqProtocol)
- private static final CIMReqProtocol DEFAULT_INSTANCE;
- static {
- DEFAULT_INSTANCE = new CIMReqProtocol();
- }
-
- public static CIMReqProtocol getDefaultInstance() {
- return DEFAULT_INSTANCE;
- }
-
- @Deprecated public static final com.google.protobuf.Parser
- PARSER = new com.google.protobuf.AbstractParser() {
- public CIMReqProtocol parsePartialFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return new CIMReqProtocol(input, extensionRegistry);
- }
- };
-
- public static com.google.protobuf.Parser parser() {
- return PARSER;
- }
-
- @Override
- public com.google.protobuf.Parser getParserForType() {
- return PARSER;
- }
-
- public CIMReqProtocol getDefaultInstanceForType() {
- return DEFAULT_INSTANCE;
- }
-
- }
-
- private static final com.google.protobuf.Descriptors.Descriptor
- internal_static_protocol_CIMReqProtocol_descriptor;
- private static final
- com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
- internal_static_protocol_CIMReqProtocol_fieldAccessorTable;
-
- public static com.google.protobuf.Descriptors.FileDescriptor
- getDescriptor() {
- return descriptor;
- }
- private static com.google.protobuf.Descriptors.FileDescriptor
- descriptor;
- static {
- String[] descriptorData = {
- "\n\026BaseRequestProto.proto\022\010protocol\"A\n\016CI" +
- "MReqProtocol\022\021\n\trequestId\030\002 \002(\003\022\016\n\006reqMs" +
- "g\030\001 \002(\t\022\014\n\004type\030\003 \002(\005B7\n$com.crossoverji" +
- "e.cim.common.protocolB\017CIMRequestProto"
- };
- com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
- new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
- public com.google.protobuf.ExtensionRegistry assignDescriptors(
- com.google.protobuf.Descriptors.FileDescriptor root) {
- descriptor = root;
- return null;
- }
- };
- com.google.protobuf.Descriptors.FileDescriptor
- .internalBuildGeneratedFileFrom(descriptorData,
- new com.google.protobuf.Descriptors.FileDescriptor[] {
- }, assigner);
- internal_static_protocol_CIMReqProtocol_descriptor =
- getDescriptor().getMessageTypes().get(0);
- internal_static_protocol_CIMReqProtocol_fieldAccessorTable = new
- com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
- internal_static_protocol_CIMReqProtocol_descriptor,
- new String[] { "RequestId", "ReqMsg", "Type", });
- }
-
- // @@protoc_insertion_point(outer_class_scope)
-}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/protocol/CIMResponseProto.java b/cim-common/src/main/java/com/crossoverjie/cim/common/protocol/CIMResponseProto.java
deleted file mode 100644
index 31bb4668..00000000
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/protocol/CIMResponseProto.java
+++ /dev/null
@@ -1,812 +0,0 @@
-// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: BaseResponseProto.proto
-
-package com.crossoverjie.cim.common.protocol;
-
-public final class CIMResponseProto {
- private CIMResponseProto() {}
- public static void registerAllExtensions(
- com.google.protobuf.ExtensionRegistryLite registry) {
- }
-
- public static void registerAllExtensions(
- com.google.protobuf.ExtensionRegistry registry) {
- registerAllExtensions(
- (com.google.protobuf.ExtensionRegistryLite) registry);
- }
- public interface CIMResProtocolOrBuilder extends
- // @@protoc_insertion_point(interface_extends:protocol.CIMResProtocol)
- com.google.protobuf.MessageOrBuilder {
-
- /**
- * required int64 responseId = 2;
- */
- boolean hasResponseId();
- /**
- * required int64 responseId = 2;
- */
- long getResponseId();
-
- /**
- * required string resMsg = 1;
- */
- boolean hasResMsg();
- /**
- * required string resMsg = 1;
- */
- String getResMsg();
- /**
- * required string resMsg = 1;
- */
- com.google.protobuf.ByteString
- getResMsgBytes();
-
- /**
- * required int32 type = 3;
- */
- boolean hasType();
- /**
- * required int32 type = 3;
- */
- int getType();
- }
- /**
- * Protobuf type {@code protocol.CIMResProtocol}
- */
- public static final class CIMResProtocol extends
- com.google.protobuf.GeneratedMessageV3 implements
- // @@protoc_insertion_point(message_implements:protocol.CIMResProtocol)
- CIMResProtocolOrBuilder {
- private static final long serialVersionUID = 0L;
- // Use CIMResProtocol.newBuilder() to construct.
- private CIMResProtocol(com.google.protobuf.GeneratedMessageV3.Builder> builder) {
- super(builder);
- }
- private CIMResProtocol() {
- responseId_ = 0L;
- resMsg_ = "";
- type_ = 0;
- }
-
- @Override
- public final com.google.protobuf.UnknownFieldSet
- getUnknownFields() {
- return this.unknownFields;
- }
- private CIMResProtocol(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- this();
- if (extensionRegistry == null) {
- throw new NullPointerException();
- }
- int mutable_bitField0_ = 0;
- com.google.protobuf.UnknownFieldSet.Builder unknownFields =
- com.google.protobuf.UnknownFieldSet.newBuilder();
- try {
- boolean done = false;
- while (!done) {
- int tag = input.readTag();
- switch (tag) {
- case 0:
- done = true;
- break;
- default: {
- if (!parseUnknownField(
- input, unknownFields, extensionRegistry, tag)) {
- done = true;
- }
- break;
- }
- case 10: {
- com.google.protobuf.ByteString bs = input.readBytes();
- bitField0_ |= 0x00000002;
- resMsg_ = bs;
- break;
- }
- case 16: {
- bitField0_ |= 0x00000001;
- responseId_ = input.readInt64();
- break;
- }
- case 24: {
- bitField0_ |= 0x00000004;
- type_ = input.readInt32();
- break;
- }
- }
- }
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- throw e.setUnfinishedMessage(this);
- } catch (java.io.IOException e) {
- throw new com.google.protobuf.InvalidProtocolBufferException(
- e).setUnfinishedMessage(this);
- } finally {
- this.unknownFields = unknownFields.build();
- makeExtensionsImmutable();
- }
- }
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return CIMResponseProto.internal_static_protocol_CIMResProtocol_descriptor;
- }
-
- protected FieldAccessorTable
- internalGetFieldAccessorTable() {
- return CIMResponseProto.internal_static_protocol_CIMResProtocol_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- CIMResProtocol.class, Builder.class);
- }
-
- private int bitField0_;
- public static final int RESPONSEID_FIELD_NUMBER = 2;
- private long responseId_;
- /**
- * required int64 responseId = 2;
- */
- public boolean hasResponseId() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * required int64 responseId = 2;
- */
- public long getResponseId() {
- return responseId_;
- }
-
- public static final int RESMSG_FIELD_NUMBER = 1;
- private volatile Object resMsg_;
- /**
- * required string resMsg = 1;
- */
- public boolean hasResMsg() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * required string resMsg = 1;
- */
- public String getResMsg() {
- Object ref = resMsg_;
- if (ref instanceof String) {
- return (String) ref;
- } else {
- com.google.protobuf.ByteString bs =
- (com.google.protobuf.ByteString) ref;
- String s = bs.toStringUtf8();
- if (bs.isValidUtf8()) {
- resMsg_ = s;
- }
- return s;
- }
- }
- /**
- * required string resMsg = 1;
- */
- public com.google.protobuf.ByteString
- getResMsgBytes() {
- Object ref = resMsg_;
- if (ref instanceof String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (String) ref);
- resMsg_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
-
- public static final int TYPE_FIELD_NUMBER = 3;
- private int type_;
- /**
- * required int32 type = 3;
- */
- public boolean hasType() {
- return ((bitField0_ & 0x00000004) == 0x00000004);
- }
- /**
- * required int32 type = 3;
- */
- public int getType() {
- return type_;
- }
-
- private byte memoizedIsInitialized = -1;
- public final boolean isInitialized() {
- byte isInitialized = memoizedIsInitialized;
- if (isInitialized == 1) return true;
- if (isInitialized == 0) return false;
-
- if (!hasResponseId()) {
- memoizedIsInitialized = 0;
- return false;
- }
- if (!hasResMsg()) {
- memoizedIsInitialized = 0;
- return false;
- }
- if (!hasType()) {
- memoizedIsInitialized = 0;
- return false;
- }
- memoizedIsInitialized = 1;
- return true;
- }
-
- public void writeTo(com.google.protobuf.CodedOutputStream output)
- throws java.io.IOException {
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- com.google.protobuf.GeneratedMessageV3.writeString(output, 1, resMsg_);
- }
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- output.writeInt64(2, responseId_);
- }
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
- output.writeInt32(3, type_);
- }
- unknownFields.writeTo(output);
- }
-
- public int getSerializedSize() {
- int size = memoizedSize;
- if (size != -1) return size;
-
- size = 0;
- if (((bitField0_ & 0x00000002) == 0x00000002)) {
- size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, resMsg_);
- }
- if (((bitField0_ & 0x00000001) == 0x00000001)) {
- size += com.google.protobuf.CodedOutputStream
- .computeInt64Size(2, responseId_);
- }
- if (((bitField0_ & 0x00000004) == 0x00000004)) {
- size += com.google.protobuf.CodedOutputStream
- .computeInt32Size(3, type_);
- }
- size += unknownFields.getSerializedSize();
- memoizedSize = size;
- return size;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (obj == this) {
- return true;
- }
- if (!(obj instanceof CIMResProtocol)) {
- return super.equals(obj);
- }
- CIMResProtocol other = (CIMResProtocol) obj;
-
- boolean result = true;
- result = result && (hasResponseId() == other.hasResponseId());
- if (hasResponseId()) {
- result = result && (getResponseId()
- == other.getResponseId());
- }
- result = result && (hasResMsg() == other.hasResMsg());
- if (hasResMsg()) {
- result = result && getResMsg()
- .equals(other.getResMsg());
- }
- result = result && (hasType() == other.hasType());
- if (hasType()) {
- result = result && (getType()
- == other.getType());
- }
- result = result && unknownFields.equals(other.unknownFields);
- return result;
- }
-
- @Override
- public int hashCode() {
- if (memoizedHashCode != 0) {
- return memoizedHashCode;
- }
- int hash = 41;
- hash = (19 * hash) + getDescriptor().hashCode();
- if (hasResponseId()) {
- hash = (37 * hash) + RESPONSEID_FIELD_NUMBER;
- hash = (53 * hash) + com.google.protobuf.Internal.hashLong(
- getResponseId());
- }
- if (hasResMsg()) {
- hash = (37 * hash) + RESMSG_FIELD_NUMBER;
- hash = (53 * hash) + getResMsg().hashCode();
- }
- if (hasType()) {
- hash = (37 * hash) + TYPE_FIELD_NUMBER;
- hash = (53 * hash) + getType();
- }
- hash = (29 * hash) + unknownFields.hashCode();
- memoizedHashCode = hash;
- return hash;
- }
-
- public static CIMResProtocol parseFrom(
- java.nio.ByteBuffer data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static CIMResProtocol parseFrom(
- java.nio.ByteBuffer data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static CIMResProtocol parseFrom(
- com.google.protobuf.ByteString data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static CIMResProtocol parseFrom(
- com.google.protobuf.ByteString data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static CIMResProtocol parseFrom(byte[] data)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data);
- }
- public static CIMResProtocol parseFrom(
- byte[] data,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return PARSER.parseFrom(data, extensionRegistry);
- }
- public static CIMResProtocol parseFrom(java.io.InputStream input)
- throws java.io.IOException {
- return com.google.protobuf.GeneratedMessageV3
- .parseWithIOException(PARSER, input);
- }
- public static CIMResProtocol parseFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return com.google.protobuf.GeneratedMessageV3
- .parseWithIOException(PARSER, input, extensionRegistry);
- }
- public static CIMResProtocol parseDelimitedFrom(java.io.InputStream input)
- throws java.io.IOException {
- return com.google.protobuf.GeneratedMessageV3
- .parseDelimitedWithIOException(PARSER, input);
- }
- public static CIMResProtocol parseDelimitedFrom(
- java.io.InputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return com.google.protobuf.GeneratedMessageV3
- .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
- }
- public static CIMResProtocol parseFrom(
- com.google.protobuf.CodedInputStream input)
- throws java.io.IOException {
- return com.google.protobuf.GeneratedMessageV3
- .parseWithIOException(PARSER, input);
- }
- public static CIMResProtocol parseFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- return com.google.protobuf.GeneratedMessageV3
- .parseWithIOException(PARSER, input, extensionRegistry);
- }
-
- public Builder newBuilderForType() { return newBuilder(); }
- public static Builder newBuilder() {
- return DEFAULT_INSTANCE.toBuilder();
- }
- public static Builder newBuilder(CIMResProtocol prototype) {
- return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
- }
- public Builder toBuilder() {
- return this == DEFAULT_INSTANCE
- ? new Builder() : new Builder().mergeFrom(this);
- }
-
- @Override
- protected Builder newBuilderForType(
- BuilderParent parent) {
- Builder builder = new Builder(parent);
- return builder;
- }
- /**
- * Protobuf type {@code protocol.CIMResProtocol}
- */
- public static final class Builder extends
- com.google.protobuf.GeneratedMessageV3.Builder implements
- // @@protoc_insertion_point(builder_implements:protocol.CIMResProtocol)
- CIMResProtocolOrBuilder {
- public static final com.google.protobuf.Descriptors.Descriptor
- getDescriptor() {
- return CIMResponseProto.internal_static_protocol_CIMResProtocol_descriptor;
- }
-
- protected FieldAccessorTable
- internalGetFieldAccessorTable() {
- return CIMResponseProto.internal_static_protocol_CIMResProtocol_fieldAccessorTable
- .ensureFieldAccessorsInitialized(
- CIMResProtocol.class, Builder.class);
- }
-
- // Construct using com.crossoverjie.cim.common.protocol.CIMResponseProto.CIMResProtocol.newBuilder()
- private Builder() {
- maybeForceBuilderInitialization();
- }
-
- private Builder(
- BuilderParent parent) {
- super(parent);
- maybeForceBuilderInitialization();
- }
- private void maybeForceBuilderInitialization() {
- if (com.google.protobuf.GeneratedMessageV3
- .alwaysUseFieldBuilders) {
- }
- }
- public Builder clear() {
- super.clear();
- responseId_ = 0L;
- bitField0_ = (bitField0_ & ~0x00000001);
- resMsg_ = "";
- bitField0_ = (bitField0_ & ~0x00000002);
- type_ = 0;
- bitField0_ = (bitField0_ & ~0x00000004);
- return this;
- }
-
- public com.google.protobuf.Descriptors.Descriptor
- getDescriptorForType() {
- return CIMResponseProto.internal_static_protocol_CIMResProtocol_descriptor;
- }
-
- public CIMResProtocol getDefaultInstanceForType() {
- return CIMResProtocol.getDefaultInstance();
- }
-
- public CIMResProtocol build() {
- CIMResProtocol result = buildPartial();
- if (!result.isInitialized()) {
- throw newUninitializedMessageException(result);
- }
- return result;
- }
-
- public CIMResProtocol buildPartial() {
- CIMResProtocol result = new CIMResProtocol(this);
- int from_bitField0_ = bitField0_;
- int to_bitField0_ = 0;
- if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
- to_bitField0_ |= 0x00000001;
- }
- result.responseId_ = responseId_;
- if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
- to_bitField0_ |= 0x00000002;
- }
- result.resMsg_ = resMsg_;
- if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
- to_bitField0_ |= 0x00000004;
- }
- result.type_ = type_;
- result.bitField0_ = to_bitField0_;
- onBuilt();
- return result;
- }
-
- public Builder clone() {
- return (Builder) super.clone();
- }
- public Builder setField(
- com.google.protobuf.Descriptors.FieldDescriptor field,
- Object value) {
- return (Builder) super.setField(field, value);
- }
- public Builder clearField(
- com.google.protobuf.Descriptors.FieldDescriptor field) {
- return (Builder) super.clearField(field);
- }
- public Builder clearOneof(
- com.google.protobuf.Descriptors.OneofDescriptor oneof) {
- return (Builder) super.clearOneof(oneof);
- }
- public Builder setRepeatedField(
- com.google.protobuf.Descriptors.FieldDescriptor field,
- int index, Object value) {
- return (Builder) super.setRepeatedField(field, index, value);
- }
- public Builder addRepeatedField(
- com.google.protobuf.Descriptors.FieldDescriptor field,
- Object value) {
- return (Builder) super.addRepeatedField(field, value);
- }
- public Builder mergeFrom(com.google.protobuf.Message other) {
- if (other instanceof CIMResProtocol) {
- return mergeFrom((CIMResProtocol)other);
- } else {
- super.mergeFrom(other);
- return this;
- }
- }
-
- public Builder mergeFrom(CIMResProtocol other) {
- if (other == CIMResProtocol.getDefaultInstance()) return this;
- if (other.hasResponseId()) {
- setResponseId(other.getResponseId());
- }
- if (other.hasResMsg()) {
- bitField0_ |= 0x00000002;
- resMsg_ = other.resMsg_;
- onChanged();
- }
- if (other.hasType()) {
- setType(other.getType());
- }
- this.mergeUnknownFields(other.unknownFields);
- onChanged();
- return this;
- }
-
- public final boolean isInitialized() {
- if (!hasResponseId()) {
- return false;
- }
- if (!hasResMsg()) {
- return false;
- }
- if (!hasType()) {
- return false;
- }
- return true;
- }
-
- public Builder mergeFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws java.io.IOException {
- CIMResProtocol parsedMessage = null;
- try {
- parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
- } catch (com.google.protobuf.InvalidProtocolBufferException e) {
- parsedMessage = (CIMResProtocol) e.getUnfinishedMessage();
- throw e.unwrapIOException();
- } finally {
- if (parsedMessage != null) {
- mergeFrom(parsedMessage);
- }
- }
- return this;
- }
- private int bitField0_;
-
- private long responseId_ ;
- /**
- * required int64 responseId = 2;
- */
- public boolean hasResponseId() {
- return ((bitField0_ & 0x00000001) == 0x00000001);
- }
- /**
- * required int64 responseId = 2;
- */
- public long getResponseId() {
- return responseId_;
- }
- /**
- * required int64 responseId = 2;
- */
- public Builder setResponseId(long value) {
- bitField0_ |= 0x00000001;
- responseId_ = value;
- onChanged();
- return this;
- }
- /**
- * required int64 responseId = 2;
- */
- public Builder clearResponseId() {
- bitField0_ = (bitField0_ & ~0x00000001);
- responseId_ = 0L;
- onChanged();
- return this;
- }
-
- private Object resMsg_ = "";
- /**
- * required string resMsg = 1;
- */
- public boolean hasResMsg() {
- return ((bitField0_ & 0x00000002) == 0x00000002);
- }
- /**
- * required string resMsg = 1;
- */
- public String getResMsg() {
- Object ref = resMsg_;
- if (!(ref instanceof String)) {
- com.google.protobuf.ByteString bs =
- (com.google.protobuf.ByteString) ref;
- String s = bs.toStringUtf8();
- if (bs.isValidUtf8()) {
- resMsg_ = s;
- }
- return s;
- } else {
- return (String) ref;
- }
- }
- /**
- * required string resMsg = 1;
- */
- public com.google.protobuf.ByteString
- getResMsgBytes() {
- Object ref = resMsg_;
- if (ref instanceof String) {
- com.google.protobuf.ByteString b =
- com.google.protobuf.ByteString.copyFromUtf8(
- (String) ref);
- resMsg_ = b;
- return b;
- } else {
- return (com.google.protobuf.ByteString) ref;
- }
- }
- /**
- * required string resMsg = 1;
- */
- public Builder setResMsg(
- String value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000002;
- resMsg_ = value;
- onChanged();
- return this;
- }
- /**
- * required string resMsg = 1;
- */
- public Builder clearResMsg() {
- bitField0_ = (bitField0_ & ~0x00000002);
- resMsg_ = getDefaultInstance().getResMsg();
- onChanged();
- return this;
- }
- /**
- * required string resMsg = 1;
- */
- public Builder setResMsgBytes(
- com.google.protobuf.ByteString value) {
- if (value == null) {
- throw new NullPointerException();
- }
- bitField0_ |= 0x00000002;
- resMsg_ = value;
- onChanged();
- return this;
- }
-
- private int type_ ;
- /**
- * required int32 type = 3;
- */
- public boolean hasType() {
- return ((bitField0_ & 0x00000004) == 0x00000004);
- }
- /**
- * required int32 type = 3;
- */
- public int getType() {
- return type_;
- }
- /**
- * required int32 type = 3;
- */
- public Builder setType(int value) {
- bitField0_ |= 0x00000004;
- type_ = value;
- onChanged();
- return this;
- }
- /**
- * required int32 type = 3;
- */
- public Builder clearType() {
- bitField0_ = (bitField0_ & ~0x00000004);
- type_ = 0;
- onChanged();
- return this;
- }
- public final Builder setUnknownFields(
- final com.google.protobuf.UnknownFieldSet unknownFields) {
- return super.setUnknownFields(unknownFields);
- }
-
- public final Builder mergeUnknownFields(
- final com.google.protobuf.UnknownFieldSet unknownFields) {
- return super.mergeUnknownFields(unknownFields);
- }
-
-
- // @@protoc_insertion_point(builder_scope:protocol.CIMResProtocol)
- }
-
- // @@protoc_insertion_point(class_scope:protocol.CIMResProtocol)
- private static final CIMResProtocol DEFAULT_INSTANCE;
- static {
- DEFAULT_INSTANCE = new CIMResProtocol();
- }
-
- public static CIMResProtocol getDefaultInstance() {
- return DEFAULT_INSTANCE;
- }
-
- @Deprecated public static final com.google.protobuf.Parser
- PARSER = new com.google.protobuf.AbstractParser() {
- public CIMResProtocol parsePartialFrom(
- com.google.protobuf.CodedInputStream input,
- com.google.protobuf.ExtensionRegistryLite extensionRegistry)
- throws com.google.protobuf.InvalidProtocolBufferException {
- return new CIMResProtocol(input, extensionRegistry);
- }
- };
-
- public static com.google.protobuf.Parser parser() {
- return PARSER;
- }
-
- @Override
- public com.google.protobuf.Parser getParserForType() {
- return PARSER;
- }
-
- public CIMResProtocol getDefaultInstanceForType() {
- return DEFAULT_INSTANCE;
- }
-
- }
-
- private static final com.google.protobuf.Descriptors.Descriptor
- internal_static_protocol_CIMResProtocol_descriptor;
- private static final
- com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
- internal_static_protocol_CIMResProtocol_fieldAccessorTable;
-
- public static com.google.protobuf.Descriptors.FileDescriptor
- getDescriptor() {
- return descriptor;
- }
- private static com.google.protobuf.Descriptors.FileDescriptor
- descriptor;
- static {
- String[] descriptorData = {
- "\n\027BaseResponseProto.proto\022\010protocol\"B\n\016C" +
- "IMResProtocol\022\022\n\nresponseId\030\002 \002(\003\022\016\n\006res" +
- "Msg\030\001 \002(\t\022\014\n\004type\030\003 \002(\005B8\n$com.crossover" +
- "jie.cim.common.protocolB\020CIMResponseProt" +
- "o"
- };
- com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
- new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
- public com.google.protobuf.ExtensionRegistry assignDescriptors(
- com.google.protobuf.Descriptors.FileDescriptor root) {
- descriptor = root;
- return null;
- }
- };
- com.google.protobuf.Descriptors.FileDescriptor
- .internalBuildGeneratedFileFrom(descriptorData,
- new com.google.protobuf.Descriptors.FileDescriptor[] {
- }, assigner);
- internal_static_protocol_CIMResProtocol_descriptor =
- getDescriptor().getMessageTypes().get(0);
- internal_static_protocol_CIMResProtocol_fieldAccessorTable = new
- com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
- internal_static_protocol_CIMResProtocol_descriptor,
- new String[] { "ResponseId", "ResMsg", "Type", });
- }
-
- // @@protoc_insertion_point(outer_class_scope)
-}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/protocol/ProtocolUtil.java b/cim-common/src/main/java/com/crossoverjie/cim/common/protocol/ProtocolUtil.java
deleted file mode 100644
index 7e811a92..00000000
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/protocol/ProtocolUtil.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.crossoverjie.cim.common.protocol;
-
-import com.google.protobuf.InvalidProtocolBufferException;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2018/8/1 12:24
- * @since JDK 1.8
- */
-public class ProtocolUtil {
-
- public static void main(String[] args) throws InvalidProtocolBufferException {
- CIMRequestProto.CIMReqProtocol protocol = CIMRequestProto.CIMReqProtocol.newBuilder()
- .setRequestId(123L)
- .setReqMsg("你好啊")
- .build();
-
- byte[] encode = encode(protocol);
-
- CIMRequestProto.CIMReqProtocol parseFrom = decode(encode);
-
- System.out.println(protocol.toString());
- System.out.println(protocol.toString().equals(parseFrom.toString()));
- }
-
- /**
- * 编码
- * @param protocol
- * @return
- */
- public static byte[] encode(CIMRequestProto.CIMReqProtocol protocol){
- return protocol.toByteArray() ;
- }
-
- /**
- * 解码
- * @param bytes
- * @return
- * @throws InvalidProtocolBufferException
- */
- public static CIMRequestProto.CIMReqProtocol decode(byte[] bytes) throws InvalidProtocolBufferException {
- return CIMRequestProto.CIMReqProtocol.parseFrom(bytes);
- }
-}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/req/BaseRequest.java b/cim-common/src/main/java/com/crossoverjie/cim/common/req/BaseRequest.java
index 1d1a5aea..2300b10a 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/req/BaseRequest.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/req/BaseRequest.java
@@ -12,10 +12,10 @@
public class BaseRequest {
- @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, description = "唯一请求号", example = "1234567890")
+ @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, description = "reqNo", example = "1234567890")
private String reqNo;
- @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, description = "当前请求的时间戳", example = "0")
+ @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, description = "timestamp", example = "0")
private int timeStamp;
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/RouteHandle.java b/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/RouteHandle.java
index 74a8a0d8..a68113ef 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/RouteHandle.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/RouteHandle.java
@@ -1,5 +1,6 @@
package com.crossoverjie.cim.common.route.algorithm;
+import com.crossoverjie.cim.common.pojo.RouteInfo;
import java.util.List;
/**
@@ -17,5 +18,8 @@ public interface RouteHandle {
* @param key
* @return
*/
+ // TODO: 2024/9/13 Use List instead of List to make the code more type-safe
String routeServer(List values,String key) ;
+
+ List removeExpireServer(RouteInfo routeInfo);
}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/AbstractConsistentHash.java b/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/AbstractConsistentHash.java
index 73307b36..015993aa 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/AbstractConsistentHash.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/AbstractConsistentHash.java
@@ -4,6 +4,7 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
+import java.util.Map;
/**
* Function:一致性 hash 算法抽象类
@@ -21,6 +22,18 @@ public abstract class AbstractConsistentHash {
*/
protected abstract void add(long key,String value);
+ /**
+ * remove node
+ * @param value node
+ * @return current data
+ */
+ protected abstract Map remove(String value);
+
+ /**
+ * Clear old data in the structure
+ */
+ protected abstract void clear();
+
/**
* 排序节点,数据结构自身支持排序可以不用重写
*/
@@ -40,7 +53,8 @@ protected void sort(){}
* @return
*/
public String process(List values,String key){
-
+ // fix https://github.com/crossoverJie/cim/issues/79
+ clear();
for (String value : values) {
add(hash(value), value);
}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/ConsistentHashHandle.java b/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/ConsistentHashHandle.java
index b0eb4621..9a58a2d5 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/ConsistentHashHandle.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/ConsistentHashHandle.java
@@ -1,8 +1,12 @@
package com.crossoverjie.cim.common.route.algorithm.consistenthash;
+import com.crossoverjie.cim.common.pojo.RouteInfo;
import com.crossoverjie.cim.common.route.algorithm.RouteHandle;
+import com.crossoverjie.cim.common.util.RouteInfoParseUtil;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* Function:
@@ -22,4 +26,10 @@ public void setHash(AbstractConsistentHash hash) {
public String routeServer(List values, String key) {
return hash.process(values, key);
}
+
+ @Override
+ public List removeExpireServer(RouteInfo routeInfo) {
+ Map remove = hash.remove(RouteInfoParseUtil.parse(routeInfo));
+ return new ArrayList<>(remove.keySet());
+ }
}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/SortArrayMapConsistentHash.java b/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/SortArrayMapConsistentHash.java
index ed7f17ee..a328a9f8 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/SortArrayMapConsistentHash.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/SortArrayMapConsistentHash.java
@@ -1,6 +1,12 @@
package com.crossoverjie.cim.common.route.algorithm.consistenthash;
import com.crossoverjie.cim.common.data.construct.SortArrayMap;
+import com.google.common.annotations.VisibleForTesting;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
/**
* Function:自定义排序 Map 实现
@@ -20,24 +26,41 @@ public class SortArrayMapConsistentHash extends AbstractConsistentHash {
@Override
public void add(long key, String value) {
- // fix https://github.com/crossoverJie/cim/issues/79
- sortArrayMap.clear();
for (int i = 0; i < VIRTUAL_NODE_SIZE; i++) {
Long hash = super.hash("vir" + key + i);
- sortArrayMap.add(hash,value);
+ sortArrayMap.add(hash, value);
}
sortArrayMap.add(key, value);
}
+ @Override
+ protected Map remove(String value) {
+ sortArrayMap = sortArrayMap.remove(value);
+ return sortArrayMap;
+ }
+
@Override
public void sort() {
sortArrayMap.sort();
}
+ /**
+ * Used only in test.
+ * @return Return the data structure of the current algorithm.
+ */
+ @VisibleForTesting
+ public SortArrayMap getSortArrayMap() {
+ return sortArrayMap;
+ }
+
+ @Override
+ protected void clear() {
+ sortArrayMap.clear();
+ }
+
@Override
public String getFirstNodeValue(String value) {
long hash = super.hash(value);
- System.out.println("value=" + value + " hash = " + hash);
return sortArrayMap.firstNodeValue(hash);
}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/TreeMapConsistentHash.java b/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/TreeMapConsistentHash.java
index 73f9869d..ac330a3e 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/TreeMapConsistentHash.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/TreeMapConsistentHash.java
@@ -2,7 +2,12 @@
import com.crossoverjie.cim.common.enums.StatusEnum;
import com.crossoverjie.cim.common.exception.CIMException;
+import com.google.common.annotations.VisibleForTesting;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
@@ -14,7 +19,7 @@
* @since JDK 1.8
*/
public class TreeMapConsistentHash extends AbstractConsistentHash {
- private TreeMap treeMap = new TreeMap() ;
+ private final TreeMap treeMap = new TreeMap() ;
/**
* 虚拟节点数量
@@ -23,9 +28,6 @@ public class TreeMapConsistentHash extends AbstractConsistentHash {
@Override
public void add(long key, String value) {
-
- // fix https://github.com/crossoverJie/cim/issues/79
- treeMap.clear();
for (int i = 0; i < VIRTUAL_NODE_SIZE; i++) {
Long hash = super.hash("vir" + key + i);
treeMap.put(hash,value);
@@ -33,10 +35,33 @@ public void add(long key, String value) {
treeMap.put(key, value);
}
+ @Override
+ protected Map remove(String value) {
+ treeMap.entrySet().removeIf(next -> next.getValue().equals(value));
+ Map result = new HashMap<>(treeMap.entrySet().size());
+ for (Map.Entry longStringEntry : treeMap.entrySet()) {
+ result.put(longStringEntry.getValue(),"");
+ }
+ return result;
+ }
+
+ @Override
+ protected void clear() {
+ treeMap.clear();
+ }
+
+ /**
+ * Used only in test.
+ * @return Return the data structure of the current algorithm.
+ */
+ @VisibleForTesting
+ public TreeMap getTreeMap() {
+ return treeMap;
+ }
+
@Override
public String getFirstNodeValue(String value) {
long hash = super.hash(value);
- System.out.println("value=" + value + " hash = " + hash);
SortedMap last = treeMap.tailMap(hash);
if (!last.isEmpty()) {
return last.get(last.firstKey());
@@ -46,4 +71,5 @@ public String getFirstNodeValue(String value) {
}
return treeMap.firstEntry().getValue();
}
+
}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/loop/LoopHandle.java b/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/loop/LoopHandle.java
index 1d0f4859..eabca47c 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/loop/LoopHandle.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/loop/LoopHandle.java
@@ -2,8 +2,11 @@
import com.crossoverjie.cim.common.enums.StatusEnum;
import com.crossoverjie.cim.common.exception.CIMException;
+import com.crossoverjie.cim.common.pojo.RouteInfo;
import com.crossoverjie.cim.common.route.algorithm.RouteHandle;
+import com.crossoverjie.cim.common.util.RouteInfoParseUtil;
+import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
@@ -15,13 +18,16 @@
* @since JDK 1.8
*/
public class LoopHandle implements RouteHandle {
- private AtomicLong index = new AtomicLong();
+ private final AtomicLong index = new AtomicLong();
+
+ private List values;
@Override
public String routeServer(List values,String key) {
if (values.size() == 0) {
throw new CIMException(StatusEnum.SERVER_NOT_AVAILABLE) ;
}
+ this.values = values;
Long position = index.incrementAndGet() % values.size();
if (position < 0) {
position = 0L;
@@ -29,4 +35,11 @@ public String routeServer(List values,String key) {
return values.get(position.intValue());
}
+
+ @Override
+ public List removeExpireServer(RouteInfo routeInfo) {
+ String parse = RouteInfoParseUtil.parse(routeInfo);
+ values.removeIf(next -> next.equals(parse));
+ return values;
+ }
}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/random/RandomHandle.java b/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/random/RandomHandle.java
index 55e742fe..6775410c 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/random/RandomHandle.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/route/algorithm/random/RandomHandle.java
@@ -2,8 +2,10 @@
import com.crossoverjie.cim.common.enums.StatusEnum;
import com.crossoverjie.cim.common.exception.CIMException;
+import com.crossoverjie.cim.common.pojo.RouteInfo;
import com.crossoverjie.cim.common.route.algorithm.RouteHandle;
+import com.crossoverjie.cim.common.util.RouteInfoParseUtil;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
@@ -16,14 +18,23 @@
*/
public class RandomHandle implements RouteHandle {
+ private List values;
@Override
public String routeServer(List values, String key) {
int size = values.size();
if (size == 0) {
throw new CIMException(StatusEnum.SERVER_NOT_AVAILABLE) ;
}
+ this.values = values;
int offset = ThreadLocalRandom.current().nextInt(size);
return values.get(offset);
}
+
+ @Override
+ public List removeExpireServer(RouteInfo routeInfo) {
+ String parse = RouteInfoParseUtil.parse(routeInfo);
+ values.removeIf(next -> next.equals(parse));
+ return values;
+ }
}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/util/HttpClient.java b/cim-common/src/main/java/com/crossoverjie/cim/common/util/HttpClient.java
index 3a80a1d7..a1e4156e 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/util/HttpClient.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/util/HttpClient.java
@@ -15,11 +15,11 @@
* Date: 2020-04-25 00:39
* @since JDK 1.8
*/
-public final class HttpClient {
+public final class HttpClient{
private static MediaType mediaType = MediaType.parse("application/json");
- public static Response call(OkHttpClient okHttpClient, String params, String url) throws IOException {
+ public static Response post(OkHttpClient okHttpClient, String params, String url) throws IOException {
RequestBody requestBody = RequestBody.create(mediaType, params);
Request request = new Request.Builder()
@@ -27,6 +27,20 @@ public static Response call(OkHttpClient okHttpClient, String params, String url
.post(requestBody)
.build();
+ Response response = okHttpClient.newCall(request).execute();
+ if (!response.isSuccessful()) {
+ throw new IOException("RPC failed unexpected code " + response);
+ }
+
+ return response;
+ }
+
+ public static Response get(OkHttpClient okHttpClient, String url) throws IOException {
+ Request request = new Request.Builder()
+ .url(url)
+ .get()
+ .build();
+
Response response = okHttpClient.newCall(request).execute();
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
@@ -34,4 +48,5 @@ public static Response call(OkHttpClient okHttpClient, String params, String url
return response;
}
+
}
diff --git a/cim-common/src/main/java/com/crossoverjie/cim/common/util/RouteInfoParseUtil.java b/cim-common/src/main/java/com/crossoverjie/cim/common/util/RouteInfoParseUtil.java
index 22bb7345..045b1237 100644
--- a/cim-common/src/main/java/com/crossoverjie/cim/common/util/RouteInfoParseUtil.java
+++ b/cim-common/src/main/java/com/crossoverjie/cim/common/util/RouteInfoParseUtil.java
@@ -17,10 +17,16 @@ public class RouteInfoParseUtil {
public static RouteInfo parse(String info){
try {
String[] serverInfo = info.split(":");
- RouteInfo routeInfo = new RouteInfo(serverInfo[0], Integer.parseInt(serverInfo[1]),Integer.parseInt(serverInfo[2])) ;
- return routeInfo ;
+ return new RouteInfo(serverInfo[0], Integer.parseInt(serverInfo[1]),Integer.parseInt(serverInfo[2]));
}catch (Exception e){
throw new CIMException(VALIDATION_FAIL) ;
}
}
+
+ public static String parse(RouteInfo routeInfo){
+ return routeInfo.getIp() + ":" + routeInfo.getCimServerPort() + ":" + routeInfo.getHttpPort();
+ }
+
+ private RouteInfoParseUtil() {
+ }
}
diff --git a/cim-common/src/main/proto/cim.proto b/cim-common/src/main/proto/cim.proto
new file mode 100644
index 00000000..3b38289b
--- /dev/null
+++ b/cim-common/src/main/proto/cim.proto
@@ -0,0 +1,24 @@
+syntax = "proto3";
+package com.crossoverjie.cim.common.protocol;
+option java_package = "com.crossoverjie.cim.common.protocol";
+option java_multiple_files = true;
+
+message Request{
+ int64 requestId = 2;
+ string reqMsg = 1;
+ BaseCommand cmd = 3;
+ map properties = 4;
+}
+
+message Response{
+ int64 responseId = 2;
+ string resMsg = 1;
+ BaseCommand cmd = 3;
+ map properties = 4;
+}
+
+enum BaseCommand{
+ LOGIN_REQUEST = 0;
+ MESSAGE = 1;
+ PING = 2;
+}
\ No newline at end of file
diff --git a/cim-common/src/test/java/com/crossoverjie/cim/common/CommonTest.java b/cim-common/src/test/java/com/crossoverjie/cim/common/CommonTest.java
index 45c24fcf..c35b9af8 100644
--- a/cim-common/src/test/java/com/crossoverjie/cim/common/CommonTest.java
+++ b/cim-common/src/test/java/com/crossoverjie/cim/common/CommonTest.java
@@ -1,5 +1,11 @@
package com.crossoverjie.cim.common;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
import org.junit.Test;
import java.time.LocalDate;
@@ -39,7 +45,6 @@ public void test() throws InterruptedException {
System.out.println(cycleNum(256,64)) ;
- cycle();
}
@@ -79,4 +84,6 @@ private void cycle() throws InterruptedException {
}
}
+
+
}
diff --git a/cim-common/src/test/java/com/crossoverjie/cim/common/core/proxy/RpcProxyManagerTest.java b/cim-common/src/test/java/com/crossoverjie/cim/common/core/proxy/RpcProxyManagerTest.java
new file mode 100644
index 00000000..c1c43c02
--- /dev/null
+++ b/cim-common/src/test/java/com/crossoverjie/cim/common/core/proxy/RpcProxyManagerTest.java
@@ -0,0 +1,210 @@
+package com.crossoverjie.cim.common.core.proxy;
+
+import com.crossoverjie.cim.common.exception.CIMException;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import okhttp3.OkHttpClient;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+class RpcProxyManagerTest {
+
+ @Test
+ public void testGet() {
+ OkHttpClient client = new OkHttpClient();
+ String url = "https://api.github.com/users";
+ Github github = RpcProxyManager.create(Github.class, url, client);
+ GithubResponse githubResponse = github.crossoverjie();
+ Assertions.assertEquals(githubResponse.getName(), "crossoverJie");
+ github.torvalds();
+ }
+
+ @Test
+ public void testPost() {
+ OkHttpClient client = new OkHttpClient();
+ String url = "http://echo.free.beeceptor.com";
+ Echo echo = RpcProxyManager.create(Echo.class, url, client);
+ EchoRequest request = new EchoRequest();
+ request.setName("crossoverJie");
+ request.setAge(18);
+ request.setCity("shenzhen");
+ EchoResponse response = echo.echo(request);
+ Assertions.assertEquals(response.getParsedBody().getName(), "crossoverJie");
+ Assertions.assertEquals(response.getParsedBody().getAge(), 18);
+ Assertions.assertEquals(response.getParsedBody().getCity(), "shenzhen");
+ }
+
+ @Test
+ public void testUrl() {
+ OkHttpClient client = new OkHttpClient();
+ String url = "http://echo.free.beeceptor.com/sample-request?author=beeceptor";
+ Echo echo = RpcProxyManager.create(Echo.class, client);
+ EchoRequest request = new EchoRequest();
+ request.setName("crossoverJie");
+ request.setAge(18);
+ request.setCity("shenzhen");
+ EchoResponse response = echo.echoTarget(url,request);
+ Assertions.assertEquals(response.getParsedBody().getName(), "crossoverJie");
+ Assertions.assertEquals(response.getParsedBody().getAge(), 18);
+ Assertions.assertEquals(response.getParsedBody().getCity(), "shenzhen");
+ response = echo.echoTarget(request, url);
+ Assertions.assertEquals(response.getParsedBody().getName(), "crossoverJie");
+
+ String req = "/request";
+ response = echo.request("http://echo.free.beeceptor.com", request);
+ Assertions.assertEquals(response.getPath(), req);
+ Assertions.assertEquals(response.getParsedBody().getAge(), 18);
+
+ Assertions.assertThrows(CIMException.class, () -> echo.echoTarget(request));
+ }
+
+ @Test
+ public void testFail() {
+ OkHttpClient client = new OkHttpClient();
+ String url = "http://echo.free.beeceptor.com";
+ Echo echo = RpcProxyManager.create(Echo.class, url, client);
+ EchoRequest request = new EchoRequest();
+ request.setName("crossoverJie");
+ request.setAge(18);
+ request.setCity("shenzhen");
+ Assertions.assertThrows(IllegalArgumentException.class, () -> echo.fail(request, "test",""));
+ }
+
+
+ @Test
+ public void testGeneric() {
+ OkHttpClient client = new OkHttpClient();
+ String url = "http://echo.free.beeceptor.com";
+ Echo echo = RpcProxyManager.create(Echo.class, url, client);
+ EchoRequest request = new EchoRequest();
+ request.setName("crossoverJie");
+ request.setAge(18);
+ request.setCity("shenzhen");
+ EchoGeneric response = echo.echoGeneric(request);
+ Assertions.assertEquals(response.getHeaders().getHost(), "echo.free.beeceptor.com");
+ }
+
+ interface Echo {
+ @Request(url = "sample-request?author=beeceptor")
+ EchoResponse echo(EchoRequest message);
+
+ @Request(url = "sample-request?author=beeceptor")
+ EchoResponse echoTarget(@DynamicUrl(useMethodEndpoint = false) String url, EchoRequest message);
+ EchoResponse echoTarget(EchoRequest message, @DynamicUrl(useMethodEndpoint = false) String url);
+ @Request(url = "sample-request?author=beeceptor")
+ EchoResponse echoTarget(@DynamicUrl EchoRequest message);
+ EchoResponse request(@DynamicUrl() String url, EchoRequest message);
+ @Request(url = "sample-request?author=beeceptor")
+ EchoResponse fail(EchoRequest message, String s, String s1);
+
+ @Request(url = "sample-request?author=beeceptor")
+ EchoGeneric echoGeneric(EchoRequest message);
+ }
+
+ @Data
+ public static class EchoRequest{
+ private String name;
+ private int age;
+ private String city;
+ }
+
+ @Data
+ @AllArgsConstructor
+ @NoArgsConstructor
+ public static class CIMServerResVO implements Serializable {
+
+ private String ip ;
+ private Integer cimServerPort;
+ private Integer httpPort;
+
+ }
+
+ @Data
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ @AllArgsConstructor
+ @NoArgsConstructor
+ public static class EchoGeneric {
+ private String method;
+ private String protocol;
+ private String host;
+
+ private T headers;
+ }
+
+ @NoArgsConstructor
+ @Data
+ public static class EchoResponse{
+
+ @JsonProperty("method")
+ private String method;
+ @JsonProperty("protocol")
+ private String protocol;
+ @JsonProperty("host")
+ private String host;
+ @JsonProperty("path")
+ private String path;
+ @JsonProperty("ip")
+ private String ip;
+ @JsonProperty("headers")
+ private HeadersDTO headers;
+ @JsonProperty("parsedQueryParams")
+ private ParsedQueryParamsDTO parsedQueryParams;
+ @JsonProperty("parsedBody")
+ private ParsedBodyDTO parsedBody;
+
+ @NoArgsConstructor
+ @Data
+ public static class HeadersDTO {
+ @JsonProperty("Host")
+ private String host;
+ @JsonProperty("User-Agent")
+ private String userAgent;
+ @JsonProperty("Content-Length")
+ private String contentLength;
+ @JsonProperty("Accept")
+ private String accept;
+ @JsonProperty("Content-Type")
+ private String contentType;
+ @JsonProperty("Accept-Encoding")
+ private String acceptEncoding;
+ }
+
+ @NoArgsConstructor
+ @Data
+ public static class ParsedQueryParamsDTO {
+ @JsonProperty("author")
+ private String author;
+ }
+
+ @NoArgsConstructor
+ @Data
+ public static class ParsedBodyDTO {
+ @JsonProperty("name")
+ private String name;
+ @JsonProperty("age")
+ private Integer age;
+ @JsonProperty("city")
+ private String city;
+ }
+ }
+
+ interface Github {
+ @Request(method = Request.GET)
+ GithubResponse crossoverjie();
+
+ @Request(method = Request.GET)
+ void torvalds();
+ }
+
+ @Data
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class GithubResponse {
+ @JsonProperty("name")
+ private String name;
+ }
+}
\ No newline at end of file
diff --git a/cim-common/src/test/java/com/crossoverjie/cim/common/metastore/MetaStoreTest.java b/cim-common/src/test/java/com/crossoverjie/cim/common/metastore/MetaStoreTest.java
new file mode 100644
index 00000000..8f415bb9
--- /dev/null
+++ b/cim-common/src/test/java/com/crossoverjie/cim/common/metastore/MetaStoreTest.java
@@ -0,0 +1,105 @@
+package com.crossoverjie.cim.common.metastore;
+
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import lombok.SneakyThrows;
+import org.I0Itec.zkclient.ZkClient;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.api.CuratorWatcher;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.data.Stat;
+import org.junit.Test;
+
+public class MetaStoreTest {
+
+ private static final String connectionString = "127.0.0.1:2181";
+
+ // TODO: 2024/8/30 integration test
+ @SneakyThrows
+// @Test
+ public void testZk() {
+ ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3);
+ CuratorFramework client = CuratorFrameworkFactory.builder()
+ .connectString(connectionString)
+ .retryPolicy(retryPolicy)
+ .connectionTimeoutMs(5000)
+ .sessionTimeoutMs(5000)
+ .build();
+ client.start();
+
+ Stat stat = client.checkExists().forPath("/cim");
+ if (stat == null) {
+ create(client, "/cim", null);
+ }
+
+
+ List list = null;
+ list = curatorWatcherGetChildren(client, "/cim", watchedEvent -> {
+ String name = Thread.currentThread().getName();
+ System.out.println("watchedEvent = " + watchedEvent + " name = " + name);
+// try {
+// List children = watchedGetChildren(client, "/cim");
+// System.out.println("children = " + children);
+// } catch (Exception e) {
+// throw new RuntimeException(e);
+// }
+ });
+
+ System.out.println(list);
+
+// createEphemeral(client, "/cim/route1", null);
+// createEphemeral(client, "/cim/route2", null);
+ TimeUnit.SECONDS.sleep(1000);
+ }
+
+ public static void createEphemeral(CuratorFramework client, String path, byte[] payload) throws Exception {
+ // this will create the given EPHEMERAL ZNode with the given data
+ client.create().withMode(CreateMode.EPHEMERAL).forPath(path, payload);
+ }
+
+ public static void create(CuratorFramework client, String path, byte[] payload) throws Exception {
+ // this will create the given ZNode with the given data
+ client.create().forPath(path, payload);
+ }
+
+
+ public static List watchedGetChildren(CuratorFramework client, String path) throws Exception {
+ /**
+ * Get children and set a watcher on the node. The watcher notification will come through the
+ * CuratorListener (see setDataAsync() above).
+ */
+ return client.getChildren().watched().forPath(path);
+ }
+
+ public static List watchedGetChildren(CuratorFramework client, String path, Watcher watcher)
+ throws Exception {
+ /**
+ * Get children and set the given watcher on the node.
+ */
+ return client.getChildren().usingWatcher(watcher).forPath(path);
+ }
+
+ public static List curatorWatcherGetChildren(CuratorFramework client, String path, CuratorWatcher watcher)
+ throws Exception {
+ /**
+ * Get children and set the given watcher on the node.
+ */
+ return client.getChildren().usingWatcher(watcher).forPath(path);
+ }
+
+
+ @SneakyThrows
+// @Test
+ public void zkClientTest(){
+ ZkClient zkClient = new ZkClient(connectionString, 5000);
+ zkClient.subscribeChildChanges("/cim", (parentPath, currentChildren) -> {
+ System.out.println("parentPath = " + parentPath);
+ System.out.println("currentChildren = " + currentChildren);
+ });
+ TimeUnit.SECONDS.sleep(1000);
+ }
+}
\ No newline at end of file
diff --git a/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/ConsistentHashHandleTest.java b/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/ConsistentHashHandleTest.java
new file mode 100644
index 00000000..60190610
--- /dev/null
+++ b/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/ConsistentHashHandleTest.java
@@ -0,0 +1,52 @@
+package com.crossoverjie.cim.common.route.algorithm.consistenthash;
+
+import static org.junit.jupiter.api.Assertions.*;
+import com.crossoverjie.cim.common.pojo.RouteInfo;
+import com.crossoverjie.cim.common.route.algorithm.RouteHandle;
+import com.crossoverjie.cim.common.util.RouteInfoParseUtil;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ConsistentHashHandleTest {
+
+ @Test
+ void removeSortMapExpireServer() {
+ ConsistentHashHandle routeHandle = new ConsistentHashHandle();
+ routeHandle.setHash(new SortArrayMapConsistentHash());
+ List strings = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ var routeInfo = new RouteInfo("127.0.0." + i, 1000, 2000);
+ strings.add(RouteInfoParseUtil.parse(routeInfo));
+ }
+ RouteInfo routeInfo = new RouteInfo("127.0.0.9", 1000, 2000);
+ String parse = RouteInfoParseUtil.parse(routeInfo);
+ String r1 = routeHandle.routeServer(strings, parse);
+ String r2 = routeHandle.routeServer(strings, parse);
+ assertEquals(r1, r2);
+
+ List list = routeHandle.removeExpireServer(routeInfo);
+ boolean contains = list.contains(parse);
+ assertFalse(contains);
+ }
+ @Test
+ void removeTreeMapExpireServer() {
+ ConsistentHashHandle routeHandle = new ConsistentHashHandle();
+ routeHandle.setHash(new TreeMapConsistentHash());
+ List strings = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ var routeInfo = new RouteInfo("127.0.0." + i, 1000, 2000);
+ strings.add(RouteInfoParseUtil.parse(routeInfo));
+ }
+ RouteInfo routeInfo = new RouteInfo("127.0.0.9", 1000, 2000);
+ String parse = RouteInfoParseUtil.parse(routeInfo);
+ String r1 = routeHandle.routeServer(strings, parse);
+ String r2 = routeHandle.routeServer(strings, parse);
+ assertEquals(r1, r2);
+
+ List list = routeHandle.removeExpireServer(routeInfo);
+ boolean contains = list.contains(parse);
+ assertFalse(contains);
+ }
+}
\ No newline at end of file
diff --git a/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/RangeCheckTestUtil.java b/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/RangeCheckTestUtil.java
new file mode 100644
index 00000000..b36ebee0
--- /dev/null
+++ b/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/RangeCheckTestUtil.java
@@ -0,0 +1,15 @@
+package com.crossoverjie.cim.common.route.algorithm.consistenthash;
+
+import org.junit.Assert;
+
+/**
+ * @description: TODO
+ * @author: zhangguoa
+ * @date: 2024/9/12 9:58
+ * @project: cim
+ */
+public class RangeCheckTestUtil {
+ public static void assertInRange (int value, int l, int r) {
+ Assert.assertTrue(value >= l && value <= r);
+ }
+}
diff --git a/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/SortArrayMapConsistentHashTest.java b/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/SortArrayMapConsistentHashTest.java
index eede2235..97df099e 100644
--- a/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/SortArrayMapConsistentHashTest.java
+++ b/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/SortArrayMapConsistentHashTest.java
@@ -1,10 +1,11 @@
package com.crossoverjie.cim.common.route.algorithm.consistenthash;
+import com.crossoverjie.cim.common.data.construct.SortArrayMap;
import org.junit.Assert;
import org.junit.Test;
-import java.util.ArrayList;
-import java.util.List;
+import java.lang.reflect.Field;
+import java.util.*;
public class SortArrayMapConsistentHashTest {
@@ -12,42 +13,46 @@ public class SortArrayMapConsistentHashTest {
public void getFirstNodeValue() {
AbstractConsistentHash map = new SortArrayMapConsistentHash() ;
- List strings = new ArrayList();
+ List strings = new ArrayList<>();
for (int i = 0; i < 10; i++) {
strings.add("127.0.0." + i) ;
}
- String process = map.process(strings,"zhangsan");
- System.out.println(process);
- Assert.assertEquals("127.0.0.2",process);
-
+ String PROCESS = map.process(strings, "zhangsan");
+ for (int i = 0; i < 100; i++) {
+ String process = map.process(strings, "zhangsan");
+ Assert.assertEquals(PROCESS, process);
+ }
}
@Test
public void getFirstNodeValue2() {
AbstractConsistentHash map = new SortArrayMapConsistentHash() ;
- List strings = new ArrayList();
+ List strings = new ArrayList<>();
for (int i = 0; i < 10; i++) {
strings.add("127.0.0." + i) ;
}
- String process = map.process(strings,"zhangsan2");
- System.out.println(process);
- Assert.assertEquals("127.0.0.3",process);
+ String PROCESS = map.process(strings,"zhangsan2");
+ for (int i = 0; i < 100; i++) {
+ String process = map.process(strings, "zhangsan2");
+ Assert.assertEquals(PROCESS, process);
+ }
}
@Test
public void getFirstNodeValue3() {
AbstractConsistentHash map = new SortArrayMapConsistentHash() ;
- List strings = new ArrayList();
+ List strings = new ArrayList<>();
for (int i = 0; i < 10; i++) {
strings.add("127.0.0." + i) ;
}
- String process = map.process(strings,"1551253899106");
-
- System.out.println(process);
- Assert.assertEquals("127.0.0.6",process);
+ String PROCESS = map.process(strings,"1551253899106");
+ for (int i = 0; i < 100; i++) {
+ String process = map.process(strings, "1551253899106");
+ Assert.assertEquals(PROCESS, process);
+ }
}
@@ -55,60 +60,97 @@ public void getFirstNodeValue3() {
public void getFirstNodeValue4() {
AbstractConsistentHash map = new SortArrayMapConsistentHash() ;
- List strings = new ArrayList();
+ List strings = new ArrayList<>();
strings.add("45.78.28.220:9000:8081") ;
strings.add("45.78.28.220:9100:9081") ;
- String process = map.process(strings,"1551253899106");
- System.out.println(process);
- Assert.assertEquals("45.78.28.220:9000:8081",process);
+ String PROCESS = map.process(strings,"1551253899106");
+ for (int i = 0; i < 100; i++) {
+ String process = map.process(strings, "1551253899106");
+ Assert.assertEquals(PROCESS, process);
+ }
}
@Test
public void getFirstNodeValue5() {
AbstractConsistentHash map = new SortArrayMapConsistentHash() ;
- List strings = new ArrayList();
+ List strings = new ArrayList<>();
strings.add("45.78.28.220:9000:8081") ;
strings.add("45.78.28.220:9100:9081") ;
strings.add("45.78.28.220:9100:10081") ;
- String process = map.process(strings,"1551253899106");
-
- System.out.println(process);
- Assert.assertEquals("45.78.28.220:9000:8081",process);
+ String PROCESS = map.process(strings,"1551253899106");
+ for (int i = 0; i < 100; i++) {
+ String process = map.process(strings, "1551253899106");
+ Assert.assertEquals(PROCESS, process);
+ }
}
@Test
public void getFirstNodeValue6() {
AbstractConsistentHash map = new SortArrayMapConsistentHash() ;
- List strings = new ArrayList();
+ List strings = new ArrayList<>();
strings.add("45.78.28.220:9000:8081") ;
strings.add("45.78.28.220:9100:9081") ;
strings.add("45.78.28.220:9100:10081") ;
- String process = map.process(strings,"1551253899106");
-
- System.out.println(process);
- Assert.assertEquals("45.78.28.220:9000:8081",process);
+ String PROCESS = map.process(strings,"1551253899106");
+ for (int i = 0; i < 100; i++) {
+ String process = map.process(strings, "1551253899106");
+ Assert.assertEquals(PROCESS, process);
+ }
}
@Test
public void getFirstNodeValue7() {
AbstractConsistentHash map = new SortArrayMapConsistentHash() ;
- List strings = new ArrayList();
+ List strings = new ArrayList<>();
strings.add("45.78.28.220:9000:8081") ;
strings.add("45.78.28.220:9100:9081") ;
strings.add("45.78.28.220:9100:10081") ;
strings.add("45.78.28.220:9100:00081") ;
- String process = map.process(strings,"1551253899106");
+ String PROCESS = map.process(strings,"1551253899106");
+ for (int i = 0; i < 100; i++) {
+ String process = map.process(strings, "1551253899106");
+ Assert.assertEquals(PROCESS, process);
+ }
+ }
+
+ @Test
+ public void getFirstNodeValue8() {
+ AbstractConsistentHash map = new SortArrayMapConsistentHash() ;
- System.out.println(process);
- Assert.assertEquals("45.78.28.220:9000:8081",process);
+ List strings = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ strings.add("127.0.0." + i);
+ }
+ Set processes = new HashSet<>();
+ for (int i = 0; i < 10; i++) {
+ String process = map.process(strings,"zhangsan" + i);
+ processes.add(process);
+ }
+ RangeCheckTestUtil.assertInRange(processes.size(), 2, 10);
}
+ @Test
+ public void testVirtualNode() throws NoSuchFieldException, IllegalAccessException {
+ SortArrayMapConsistentHash map = new SortArrayMapConsistentHash();
+
+ List strings = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ strings.add("127.0.0." + i);
+ }
+ String process = map.process(strings,"zhangsan");
+
+ SortArrayMap sortArrayMap = map.getSortArrayMap();
+ int virtualNodeSize = 2;
+
+ System.out.println("sortArrayMapSize = " + sortArrayMap.size() + "\n" + "virtualNodeSize = " + virtualNodeSize);
+ Assert.assertEquals(sortArrayMap.size(), (virtualNodeSize + 1) * 10);
+ }
}
\ No newline at end of file
diff --git a/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/TreeMapConsistentHashTest.java b/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/TreeMapConsistentHashTest.java
index b4f9ee3f..01060894 100644
--- a/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/TreeMapConsistentHashTest.java
+++ b/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/consistenthash/TreeMapConsistentHashTest.java
@@ -3,22 +3,26 @@
import org.junit.Assert;
import org.junit.Test;
-import java.util.ArrayList;
-import java.util.List;
+import java.lang.reflect.Field;
+import java.util.*;
public class TreeMapConsistentHashTest {
+
+
@Test
public void getFirstNodeValue() {
AbstractConsistentHash map = new TreeMapConsistentHash() ;
- List strings = new ArrayList();
+ List strings = new ArrayList<>();
for (int i = 0; i < 10; i++) {
strings.add("127.0.0." + i) ;
}
- String process = map.process(strings,"zhangsan");
- System.out.println(process);
- Assert.assertEquals("127.0.0.2",process);
+ String PROCESS = map.process(strings, "zhangsan");
+ for (int i = 0; i < 100; i++) {
+ String process = map.process(strings, "zhangsan");
+ Assert.assertEquals(PROCESS, process);
+ }
}
@@ -27,14 +31,15 @@ public void getFirstNodeValue() {
public void getFirstNodeValue2() {
AbstractConsistentHash map = new TreeMapConsistentHash() ;
- List strings = new ArrayList();
+ List strings = new ArrayList<>();
for (int i = 0; i < 10; i++) {
strings.add("127.0.0." + i) ;
}
- String process = map.process(strings,"zhangsan2");
- System.out.println(process);
-
- Assert.assertEquals("127.0.0.3",process);
+ String PROCESS = map.process(strings,"zhangsan2");
+ for (int i = 0; i < 100; i++) {
+ String process = map.process(strings, "zhangsan2");
+ Assert.assertEquals(PROCESS, process);
+ }
}
@@ -42,13 +47,48 @@ public void getFirstNodeValue2() {
public void getFirstNodeValue3() {
AbstractConsistentHash map = new TreeMapConsistentHash() ;
- List strings = new ArrayList();
+ List strings = new ArrayList<>();
for (int i = 0; i < 10; i++) {
strings.add("127.0.0." + i) ;
}
- String process = map.process(strings,"1551253899106");
+ String PROCESS = map.process(strings,"1551253899106");
+ for (int i = 0; i < 100; i++) {
+ String process = map.process(strings, "1551253899106");
+ Assert.assertEquals(PROCESS, process);
+ }
+ }
+
+ @Test
+ public void getFirstNodeValue4() {
+ AbstractConsistentHash map = new TreeMapConsistentHash() ;
+
+ List strings = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ strings.add("127.0.0." + i);
+ }
+ Set processes = new HashSet<>();
+ for (int i = 0; i < 10; i++) {
+ String process = map.process(strings,"zhangsan" + i);
+ processes.add(process);
+ }
+ RangeCheckTestUtil.assertInRange(processes.size(), 2, 10);
+ }
+
+ @Test
+ public void testVirtualNode() throws NoSuchFieldException, IllegalAccessException {
+ TreeMapConsistentHash map = new TreeMapConsistentHash();
+
+ List strings = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ strings.add("127.0.0." + i);
+ }
+
+ String process = map.process(strings,"zhangsan");
+
+ TreeMap treeMap = map.getTreeMap();
+ int virtualNodeSize = 2;
- System.out.println(process);
- Assert.assertEquals("127.0.0.6",process);
+ System.out.println("treeMapSize = " + treeMap.size() + "\n" + "virtualNodeSize = " + virtualNodeSize);
+ Assert.assertEquals(treeMap.size(), (virtualNodeSize + 1) * 10);
}
}
\ No newline at end of file
diff --git a/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/loop/LoopHandleTest.java b/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/loop/LoopHandleTest.java
new file mode 100644
index 00000000..273f15ba
--- /dev/null
+++ b/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/loop/LoopHandleTest.java
@@ -0,0 +1,30 @@
+package com.crossoverjie.cim.common.route.algorithm.loop;
+
+import static org.junit.jupiter.api.Assertions.*;
+import com.crossoverjie.cim.common.pojo.RouteInfo;
+import com.crossoverjie.cim.common.route.algorithm.RouteHandle;
+import com.crossoverjie.cim.common.util.RouteInfoParseUtil;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+class LoopHandleTest {
+
+ @Test
+ void removeExpireServer() {
+ RouteHandle routeHandle = new LoopHandle();
+ List strings = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ var routeInfo = new RouteInfo("127.0.0." + i, 1000, 2000);
+ strings.add(RouteInfoParseUtil.parse(routeInfo));
+ }
+ String zs = routeHandle.routeServer(strings, "zs");
+ String zs2 = routeHandle.routeServer(strings, "zs");
+ assertNotEquals(zs, zs2);
+
+ RouteInfo remove = new RouteInfo("127.0.0.0", 1000, 2000);
+ List list = routeHandle.removeExpireServer(remove);
+ boolean contains = list.contains(RouteInfoParseUtil.parse(remove));
+ assertFalse(contains);
+ }
+}
\ No newline at end of file
diff --git a/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/random/RandomHandleTest.java b/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/random/RandomHandleTest.java
new file mode 100644
index 00000000..2d3af96c
--- /dev/null
+++ b/cim-common/src/test/java/com/crossoverjie/cim/common/route/algorithm/random/RandomHandleTest.java
@@ -0,0 +1,29 @@
+package com.crossoverjie.cim.common.route.algorithm.random;
+
+import static org.junit.jupiter.api.Assertions.*;
+import com.crossoverjie.cim.common.pojo.RouteInfo;
+import com.crossoverjie.cim.common.route.algorithm.RouteHandle;
+import com.crossoverjie.cim.common.route.algorithm.loop.LoopHandle;
+import com.crossoverjie.cim.common.util.RouteInfoParseUtil;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+class RandomHandleTest {
+ @Test
+ void removeExpireServer() {
+ RouteHandle routeHandle = new RandomHandle();
+ List strings = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ var routeInfo = new RouteInfo("127.0.0." + i, 1000, 2000);
+ strings.add(RouteInfoParseUtil.parse(routeInfo));
+ }
+ routeHandle.routeServer(strings, "zs");
+
+ RouteInfo remove = new RouteInfo("127.0.0.0", 1000, 2000);
+ List list = routeHandle.removeExpireServer(remove);
+ boolean contains = list.contains(RouteInfoParseUtil.parse(remove));
+ assertFalse(contains);
+ }
+
+}
\ No newline at end of file
diff --git a/cim-common/src/test/java/com/crossoverjie/cim/common/util/HttpClientTest.java b/cim-common/src/test/java/com/crossoverjie/cim/common/util/HttpClientTest.java
index a809eab9..0ef260c9 100644
--- a/cim-common/src/test/java/com/crossoverjie/cim/common/util/HttpClientTest.java
+++ b/cim-common/src/test/java/com/crossoverjie/cim/common/util/HttpClientTest.java
@@ -28,6 +28,7 @@ public void call() throws IOException {
jsonObject.put("msg", "hello");
jsonObject.put("userId", 1586617710861L);
- HttpClient.call(okHttpClient,jsonObject.toString(),"http://127.0.0.1:8081/sendMsg") ;
+ // TODO: 2024/8/30 Integration test
+// HttpClient.call(okHttpClient,jsonObject.toString(),"http://127.0.0.1:8081/sendMsg") ;
}
}
\ No newline at end of file
diff --git a/cim-common/src/test/java/com/crossoverjie/cim/common/util/ProtocolTest.java b/cim-common/src/test/java/com/crossoverjie/cim/common/util/ProtocolTest.java
new file mode 100644
index 00000000..bcdd9194
--- /dev/null
+++ b/cim-common/src/test/java/com/crossoverjie/cim/common/util/ProtocolTest.java
@@ -0,0 +1,44 @@
+package com.crossoverjie.cim.common.util;
+
+import com.crossoverjie.cim.common.protocol.BaseCommand;
+import com.crossoverjie.cim.common.protocol.Request;
+import com.google.protobuf.InvalidProtocolBufferException;
+import org.junit.Test;
+
+public class ProtocolTest {
+
+ @Test
+ public void testProtocol() throws InvalidProtocolBufferException {
+ Request protocol = Request.newBuilder()
+ .setRequestId(123L)
+ .setReqMsg("你好啊")
+ .setCmd(BaseCommand.LOGIN_REQUEST)
+ .build();
+
+ byte[] encode = encode(protocol);
+
+ Request parseFrom = decode(encode);
+
+ System.out.println(protocol);
+ System.out.println(protocol.toString().equals(parseFrom.toString()));
+ }
+
+ /**
+ * 编码
+ * @param protocol
+ * @return
+ */
+ public static byte[] encode(Request protocol){
+ return protocol.toByteArray() ;
+ }
+
+ /**
+ * 解码
+ * @param bytes
+ * @return
+ * @throws InvalidProtocolBufferException
+ */
+ public static Request decode(byte[] bytes) throws InvalidProtocolBufferException {
+ return Request.parseFrom(bytes);
+ }
+}
diff --git a/cim-forward-route/pom.xml b/cim-forward-route/pom.xml
index fa6c4089..f894b29d 100644
--- a/cim-forward-route/pom.xml
+++ b/cim-forward-route/pom.xml
@@ -54,6 +54,38 @@
test
+
+ org.junit.vintage
+ junit-vintage-engine
+ test
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+
+ com.clever-cloud
+ testcontainers-zookeeper
+
+
+
+ com.redis
+ testcontainers-redis
+ test
+
+
+
+ org.testcontainers
+ testcontainers
+
+
+ org.testcontainers
+ junit-jupiter
+
+
org.springframework.boot
spring-boot-configuration-processor
@@ -88,21 +120,5 @@
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
- repackage
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/RouteApplication.java b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/RouteApplication.java
index f584d073..22849826 100644
--- a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/RouteApplication.java
+++ b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/RouteApplication.java
@@ -1,6 +1,5 @@
package com.crossoverjie.cim.route;
-import com.crossoverjie.cim.route.kit.ServerListListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
@@ -20,10 +19,5 @@ public static void main(String[] args) {
@Override
public void run(String... args) throws Exception {
-
- //监听服务
- Thread thread = new Thread(new ServerListListener());
- thread.setName("zk-listener");
- thread.start() ;
}
}
\ No newline at end of file
diff --git a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/cache/ServerCache.java b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/cache/ServerCache.java
deleted file mode 100644
index 2cf65163..00000000
--- a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/cache/ServerCache.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package com.crossoverjie.cim.route.cache;
-
-import com.crossoverjie.cim.route.kit.ZKit;
-import com.google.common.cache.LoadingCache;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Function: 服务器节点缓存
- *
- * @author crossoverJie
- * Date: 2018/8/19 01:31
- * @since JDK 1.8
- */
-@Component
-@Slf4j
-public class ServerCache {
-
-
- @Autowired
- private LoadingCache cache;
-
- @Autowired
- private ZKit zkUtil;
-
- public void addCache(String key) {
- cache.put(key, key);
- }
-
-
- /**
- * 更新所有缓存/先删除 再新增
- *
- * @param currentChildren
- */
- public void updateCache(List currentChildren) {
- cache.invalidateAll();
- for (String currentChild : currentChildren) {
- // currentChildren=ip-127.0.0.1:11212:9082 or 127.0.0.1:11212:9082
- String key ;
- if (currentChild.split("-").length == 2){
- key = currentChild.split("-")[1];
- }else {
- key = currentChild ;
- }
- addCache(key);
- }
- }
-
-
- /**
- * 获取所有的服务列表
- *
- * @return
- */
- public List getServerList() {
-
- List list = new ArrayList<>();
-
- if (cache.size() == 0) {
- List allNode = zkUtil.getAllNode();
- for (String node : allNode) {
- String key = node.split("-")[1];
- addCache(key);
- }
- }
- for (Map.Entry entry : cache.asMap().entrySet()) {
- list.add(entry.getKey());
- }
- return list;
-
- }
-
- /**
- * rebuild cache list
- */
- public void rebuildCacheList(){
- updateCache(getServerList()) ;
- }
-
-}
diff --git a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/BeanConfig.java b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/BeanConfig.java
index 1a515e6f..d43ba8ea 100644
--- a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/BeanConfig.java
+++ b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/config/BeanConfig.java
@@ -1,13 +1,22 @@
package com.crossoverjie.cim.route.config;
+import com.crossoverjie.cim.common.core.proxy.RpcProxyManager;
+import com.crossoverjie.cim.common.metastore.MetaStore;
+import com.crossoverjie.cim.common.metastore.ZkConfiguration;
+import com.crossoverjie.cim.common.metastore.ZkMetaStoreImpl;
+import com.crossoverjie.cim.common.pojo.CIMUserInfo;
import com.crossoverjie.cim.common.route.algorithm.RouteHandle;
import com.crossoverjie.cim.common.route.algorithm.consistenthash.AbstractConsistentHash;
+import com.crossoverjie.cim.server.api.ServerApi;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
+import com.google.common.cache.Weigher;
+import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import org.I0Itec.zkclient.ZkClient;
+import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -17,8 +26,12 @@
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.lang.reflect.Method;
+import java.time.Duration;
+import java.util.Optional;
import java.util.concurrent.TimeUnit;
+import static com.crossoverjie.cim.route.constant.Constant.ACCOUNT_PREFIX;
+
/**
* Function:
*
@@ -31,23 +44,23 @@
public class BeanConfig {
- @Autowired
+ @Resource
private AppConfiguration appConfiguration;
- @Bean
- public ZkClient buildZKClient() {
- return new ZkClient(appConfiguration.getZkAddr(), appConfiguration.getZkConnectTimeout());
- }
@Bean
- public LoadingCache buildCache() {
- return CacheBuilder.newBuilder()
- .build(new CacheLoader() {
- @Override
- public String load(String s) throws Exception {
- return null;
- }
- });
+ public MetaStore metaStore() throws Exception {
+ MetaStore metaStore = new ZkMetaStoreImpl();
+ ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3);
+ metaStore.initialize(ZkConfiguration.builder()
+ .metaServiceUri(appConfiguration.getZkAddr())
+ .timeoutMs(appConfiguration.getZkConnectTimeout())
+ .retryPolicy(retryPolicy)
+ .build());
+ metaStore.listenServerList((root, currentChildren) -> {
+ log.info("Server list change, root=[{}], current server list=[{}]", root, currentChildren);
+ });
+ return metaStore;
}
@@ -92,8 +105,8 @@ public RouteHandle buildRouteHandle() throws Exception {
Method method = Class.forName(routeWay).getMethod("setHash", AbstractConsistentHash.class);
AbstractConsistentHash consistentHash = (AbstractConsistentHash)
Class.forName(appConfiguration.getConsistentHashWay()).newInstance();
- method.invoke(routeHandle,consistentHash) ;
- return routeHandle ;
+ method.invoke(routeHandle, consistentHash);
+ return routeHandle;
} else {
return routeHandle;
@@ -101,4 +114,29 @@ public RouteHandle buildRouteHandle() throws Exception {
}
}
+
+ @Bean("userInfoCache")
+ public LoadingCache> userInfoCache(RedisTemplate redisTemplate) {
+ return CacheBuilder.newBuilder()
+ .initialCapacity(64)
+ .maximumSize(1024)
+ .concurrencyLevel(Runtime.getRuntime().availableProcessors())
+ .expireAfterWrite(10, TimeUnit.MINUTES)
+ .build(new CacheLoader<>() {
+ @Override
+ public Optional load(Long userId) throws Exception {
+ String sendUserName = redisTemplate.opsForValue().get(ACCOUNT_PREFIX + userId);
+ if (sendUserName == null) {
+ return Optional.empty();
+ }
+ CIMUserInfo cimUserInfo = new CIMUserInfo(userId, sendUserName);
+ return Optional.of(cimUserInfo);
+ }
+ });
+ }
+
+ @Bean
+ public ServerApi serverApi(OkHttpClient okHttpClient) {
+ return RpcProxyManager.create(ServerApi.class, okHttpClient);
+ }
}
diff --git a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/controller/RouteController.java b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/controller/RouteController.java
index c428a413..6ff84924 100644
--- a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/controller/RouteController.java
+++ b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/controller/RouteController.java
@@ -2,6 +2,7 @@
import com.crossoverjie.cim.common.enums.StatusEnum;
import com.crossoverjie.cim.common.exception.CIMException;
+import com.crossoverjie.cim.common.metastore.MetaStore;
import com.crossoverjie.cim.common.pojo.CIMUserInfo;
import com.crossoverjie.cim.common.pojo.RouteInfo;
import com.crossoverjie.cim.common.res.BaseResponse;
@@ -15,11 +16,15 @@
import com.crossoverjie.cim.route.api.vo.req.RegisterInfoReqVO;
import com.crossoverjie.cim.route.api.vo.res.CIMServerResVO;
import com.crossoverjie.cim.route.api.vo.res.RegisterInfoResVO;
-import com.crossoverjie.cim.route.cache.ServerCache;
import com.crossoverjie.cim.route.service.AccountService;
import com.crossoverjie.cim.route.service.CommonBizService;
import com.crossoverjie.cim.route.service.UserInfoCacheService;
import io.swagger.v3.oas.annotations.Operation;
+import jakarta.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@@ -28,14 +33,11 @@
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
-import java.util.Map;
-import java.util.Set;
-
/**
* Function:
*
* @author crossoverJie
- * Date: 22/05/2018 14:46
+ * Date: 22/05/2018 14:46
* @since JDK 1.8
*/
@Slf4j
@@ -43,45 +45,44 @@
@RequestMapping("/")
public class RouteController implements RouteApi {
- @Autowired
- private ServerCache serverCache;
+ @Resource
+ private MetaStore metaStore;
- @Autowired
+ @Resource
private AccountService accountService;
- @Autowired
- private UserInfoCacheService userInfoCacheService ;
+ @Resource
+ private UserInfoCacheService userInfoCacheService;
- @Autowired
- private CommonBizService commonBizService ;
+ @Resource
+ private CommonBizService commonBizService;
- @Autowired
- private RouteHandle routeHandle ;
+ @Resource
+ private RouteHandle routeHandle;
@Operation(summary = "群聊 API")
@RequestMapping(value = "groupRoute", method = RequestMethod.POST)
@ResponseBody()
@Override
- public BaseResponse groupRoute(@RequestBody ChatReqVO groupReqVO) throws Exception {
+ public BaseResponse groupRoute(@RequestBody ChatReqVO groupReqVO) {
BaseResponse res = new BaseResponse();
log.info("msg=[{}]", groupReqVO.toString());
- //获取所有的推送列表
- Map serverResVOMap = accountService.loadRouteRelated();
- for (Map.Entry cimServerResVOEntry : serverResVOMap.entrySet()) {
- Long userId = cimServerResVOEntry.getKey();
- CIMServerResVO cimServerResVO = cimServerResVOEntry.getValue();
- if (userId.equals(groupReqVO.getUserId())){
- //过滤掉自己
- CIMUserInfo cimUserInfo = userInfoCacheService.loadUserInfoByUserId(groupReqVO.getUserId());
- log.warn("过滤掉了发送者 userId={}",cimUserInfo.toString());
+ Map serverResVoMap = accountService.loadRouteRelated();
+ for (Map.Entry cimServerResVoEntry : serverResVoMap.entrySet()) {
+ Long userId = cimServerResVoEntry.getKey();
+ CIMServerResVO cimServerResVO = cimServerResVoEntry.getValue();
+ if (userId.equals(groupReqVO.getUserId())) {
+ // Skip the sender
+ Optional cimUserInfo = userInfoCacheService.loadUserInfoByUserId(groupReqVO.getUserId());
+ cimUserInfo.ifPresent(userInfo -> log.warn("skip send user userId={}", userInfo));
continue;
}
- //推送消息
- ChatReqVO chatVO = new ChatReqVO(userId,groupReqVO.getMsg()) ;
- accountService.pushMsg(cimServerResVO ,groupReqVO.getUserId(),chatVO);
+ // Push message
+ ChatReqVO chatVO = new ChatReqVO(userId, groupReqVO.getMsg());
+ accountService.pushMsg(cimServerResVO, groupReqVO.getUserId(), chatVO);
}
@@ -97,11 +98,11 @@ public BaseResponse groupRoute(@RequestBody ChatReqVO groupReqVO) thro
* @param p2pRequest
* @return
*/
- @Operation(summary = "私聊 API")
+ @Operation(summary = "私聊 API")
@RequestMapping(value = "p2pRoute", method = RequestMethod.POST)
@ResponseBody()
@Override
- public BaseResponse p2pRoute(@RequestBody P2PReqVO p2pRequest) throws Exception {
+ public BaseResponse p2pRoute(@RequestBody P2PReqVO p2pRequest) {
BaseResponse res = new BaseResponse();
try {
@@ -109,13 +110,13 @@ public BaseResponse p2pRoute(@RequestBody P2PReqVO p2pRequest) throws
CIMServerResVO cimServerResVO = accountService.loadRouteRelatedByUserId(p2pRequest.getReceiveUserId());
//p2pRequest.getReceiveUserId()==>消息接收者的 userID
- ChatReqVO chatVO = new ChatReqVO(p2pRequest.getReceiveUserId(),p2pRequest.getMsg()) ;
- accountService.pushMsg(cimServerResVO ,p2pRequest.getUserId(),chatVO);
+ ChatReqVO chatVO = new ChatReqVO(p2pRequest.getReceiveUserId(), p2pRequest.getMsg());
+ accountService.pushMsg(cimServerResVO, p2pRequest.getUserId(), chatVO);
res.setCode(StatusEnum.SUCCESS.getCode());
res.setMessage(StatusEnum.SUCCESS.getMessage());
- }catch (CIMException e){
+ } catch (CIMException e) {
res.setCode(e.getErrorCode());
res.setMessage(e.getErrorMessage());
}
@@ -127,13 +128,15 @@ public BaseResponse p2pRoute(@RequestBody P2PReqVO p2pRequest) throws
@RequestMapping(value = "offLine", method = RequestMethod.POST)
@ResponseBody()
@Override
- public BaseResponse offLine(@RequestBody ChatReqVO groupReqVO) throws Exception {
+ public BaseResponse offLine(@RequestBody ChatReqVO groupReqVO) {
BaseResponse res = new BaseResponse();
- CIMUserInfo cimUserInfo = userInfoCacheService.loadUserInfoByUserId(groupReqVO.getUserId());
+ Optional cimUserInfo = userInfoCacheService.loadUserInfoByUserId(groupReqVO.getUserId());
- log.info("user [{}] offline!", cimUserInfo.toString());
- accountService.offLine(groupReqVO.getUserId());
+ cimUserInfo.ifPresent(userInfo -> {
+ log.info("user [{}] offline!", userInfo.toString());
+ accountService.offLine(groupReqVO.getUserId());
+ });
res.setCode(StatusEnum.SUCCESS.getCode());
res.setMessage(StatusEnum.SUCCESS.getMessage());
@@ -151,28 +154,30 @@ public BaseResponse offLine(@RequestBody ChatReqVO groupReqVO) throws
@Override
public BaseResponse login(@RequestBody LoginReqVO loginReqVO) throws Exception {
BaseResponse res = new BaseResponse();
-
- // check server available
- String server = routeHandle.routeServer(serverCache.getServerList(),String.valueOf(loginReqVO.getUserId()));
- log.info("userName=[{}] route server info=[{}]", loginReqVO.getUserName(), server);
-
- RouteInfo routeInfo = RouteInfoParseUtil.parse(server);
- commonBizService.checkServerAvailable(routeInfo);
-
//登录校验
StatusEnum status = accountService.login(loginReqVO);
- if (status == StatusEnum.SUCCESS) {
+ res.setCode(status.getCode());
+ res.setMessage(status.getMessage());
+ if (status != StatusEnum.SUCCESS) {
+ return res;
+ }
- //保存路由信息
- accountService.saveRouteInfo(loginReqVO,server);
+ // check server available
+ Set availableServerList = metaStore.getAvailableServerList();
+ String key = String.valueOf(loginReqVO.getUserId());
+ String server =
+ routeHandle.routeServer(List.copyOf(availableServerList), key);
+ log.info("userInfo=[{}] route server info=[{}]", loginReqVO, server);
- CIMServerResVO vo = new CIMServerResVO(routeInfo);
- res.setDataBody(vo);
+ RouteInfo routeInfo = RouteInfoParseUtil.parse(server);
+ routeInfo = commonBizService.checkServerAvailable(routeInfo, key);
- }
- res.setCode(status.getCode());
- res.setMessage(status.getMessage());
+ //保存路由信息
+ accountService.saveRouteInfo(loginReqVO, server);
+ CIMServerResVO vo =
+ new CIMServerResVO(routeInfo.getIp(), routeInfo.getCimServerPort(), routeInfo.getHttpPort());
+ res.setDataBody(vo);
return res;
}
@@ -185,7 +190,8 @@ public BaseResponse login(@RequestBody LoginReqVO loginReqVO) th
@RequestMapping(value = "registerAccount", method = RequestMethod.POST)
@ResponseBody()
@Override
- public BaseResponse registerAccount(@RequestBody RegisterInfoReqVO registerInfoReqVO) throws Exception {
+ public BaseResponse registerAccount(@RequestBody RegisterInfoReqVO registerInfoReqVO)
+ throws Exception {
BaseResponse res = new BaseResponse();
long userId = System.currentTimeMillis();
@@ -204,14 +210,14 @@ public BaseResponse registerAccount(@RequestBody RegisterInfo
* @return
*/
@Operation(summary = "获取所有在线用户")
- @RequestMapping(value = "onlineUser", method = RequestMethod.POST)
+ @RequestMapping(value = "onlineUser", method = RequestMethod.GET)
@ResponseBody()
@Override
public BaseResponse> onlineUser() throws Exception {
BaseResponse> res = new BaseResponse();
Set cimUserInfos = userInfoCacheService.onlineUser();
- res.setDataBody(cimUserInfos) ;
+ res.setDataBody(cimUserInfos);
res.setCode(StatusEnum.SUCCESS.getCode());
res.setMessage(StatusEnum.SUCCESS.getMessage());
return res;
diff --git a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/kit/NetAddressIsReachable.java b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/kit/NetAddressIsReachable.java
index 24836557..df0458c0 100644
--- a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/kit/NetAddressIsReachable.java
+++ b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/kit/NetAddressIsReachable.java
@@ -3,6 +3,7 @@
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
+import lombok.extern.slf4j.Slf4j;
/**
* Function:
@@ -11,6 +12,7 @@
* Date: 2020-04-12 20:32
* @since JDK 1.8
*/
+@Slf4j
public class NetAddressIsReachable {
/**
@@ -32,8 +34,10 @@ public static boolean checkAddressReachable(String address, int port, int timeou
try {
socket.close();
} catch (IOException e) {
- return false ;
+ log.warn("close socket error", e);
}
}
}
+
+ private NetAddressIsReachable(){}
}
diff --git a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/kit/ServerListListener.java b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/kit/ServerListListener.java
deleted file mode 100644
index a699cc0d..00000000
--- a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/kit/ServerListListener.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.crossoverjie.cim.route.kit;
-
-import com.crossoverjie.cim.route.cache.ServerCache;
-import com.crossoverjie.cim.route.config.AppConfiguration;
-import com.crossoverjie.cim.route.util.SpringBeanFactory;
-import java.util.List;
-import lombok.extern.slf4j.Slf4j;
-import org.I0Itec.zkclient.IZkChildListener;
-import org.I0Itec.zkclient.ZkClient;
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2018/12/23 00:35
- * @since JDK 1.8
- */
-@Slf4j
-public class ServerListListener implements Runnable{
-
-
- private ZKit zkUtil;
-
- private AppConfiguration appConfiguration ;
-
- private ZkClient zkClient;
-
- private ServerCache serverCache ;
-
-
- public ServerListListener() {
- zkUtil = SpringBeanFactory.getBean(ZKit.class) ;
- appConfiguration = SpringBeanFactory.getBean(AppConfiguration.class) ;
- zkClient = SpringBeanFactory.getBean(ZkClient.class) ;
- serverCache = SpringBeanFactory.getBean(ServerCache.class) ;
- }
-
- @Override
- public void run() {
- //注册监听服务
- subscribeEvent(appConfiguration.getZkRoot());
-
- }
-
- /**
- * 监听事件
- *
- * @param path
- */
- public void subscribeEvent(String path) {
- zkClient.subscribeChildChanges(path, new IZkChildListener() {
- @Override
- public void handleChildChange(String parentPath, List currentChildren) throws Exception {
- log.info("Clear and update local cache parentPath=[{}],currentChildren=[{}]", parentPath,currentChildren.toString());
-
- //update local cache, delete and save.
- serverCache.updateCache(currentChildren) ;
- }
- });
-
-
- }
-}
diff --git a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/kit/ZKit.java b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/kit/ZKit.java
deleted file mode 100644
index c7b7ed22..00000000
--- a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/kit/ZKit.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.crossoverjie.cim.route.kit;
-
-import com.alibaba.fastjson.JSON;
-import com.crossoverjie.cim.route.config.AppConfiguration;
-import java.util.List;
-import lombok.extern.slf4j.Slf4j;
-import org.I0Itec.zkclient.ZkClient;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-/**
- * Function: Zookeeper kit
- *
- * @author crossoverJie
- * Date: 2018/8/19 00:33
- * @since JDK 1.8
- */
-@Component
-@Slf4j
-public class ZKit {
-
-
-
- @Autowired
- private ZkClient zkClient;
-
- @Autowired
- private AppConfiguration appConfiguration;
-
-
-
-
- /**
- * get all server node from zookeeper
- * @return
- */
- public List getAllNode(){
- List children = zkClient.getChildren(appConfiguration.getZkRoot());
- log.info("Query all node =[{}] success.", JSON.toJSONString(children));
- return children;
- }
-
-
-}
diff --git a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/AccountService.java b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/AccountService.java
index dd78b419..45c2738b 100644
--- a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/AccountService.java
+++ b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/AccountService.java
@@ -62,12 +62,12 @@ public interface AccountService {
* @param sendUserId 发送者的ID
* @throws Exception
*/
- void pushMsg(CIMServerResVO cimServerResVO, long sendUserId , ChatReqVO groupReqVO) throws Exception;
+ void pushMsg(CIMServerResVO cimServerResVO, long sendUserId , ChatReqVO groupReqVO);
/**
* 用户下线
* @param userId 下线用户ID
* @throws Exception
*/
- void offLine(Long userId) throws Exception;
+ void offLine(Long userId);
}
diff --git a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/CommonBizService.java b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/CommonBizService.java
index e5a9bb19..f63d0992 100644
--- a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/CommonBizService.java
+++ b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/CommonBizService.java
@@ -2,11 +2,15 @@
import com.crossoverjie.cim.common.enums.StatusEnum;
import com.crossoverjie.cim.common.exception.CIMException;
+import com.crossoverjie.cim.common.metastore.MetaStore;
import com.crossoverjie.cim.common.pojo.RouteInfo;
-import com.crossoverjie.cim.route.cache.ServerCache;
+import com.crossoverjie.cim.common.route.algorithm.RouteHandle;
+import com.crossoverjie.cim.common.util.RouteInfoParseUtil;
import com.crossoverjie.cim.route.kit.NetAddressIsReachable;
+import jakarta.annotation.Resource;
+import java.util.List;
+import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
@@ -21,23 +25,23 @@
public class CommonBizService {
- @Autowired
- private ServerCache serverCache ;
+ @Resource
+ private RouteHandle routeHandle;
/**
- * check ip and port
+ * check ip and port, and return a new server if the current server is not available
* @param routeInfo
*/
- public void checkServerAvailable(RouteInfo routeInfo){
+ @SneakyThrows
+ public RouteInfo checkServerAvailable(RouteInfo routeInfo, String userId){
boolean reachable = NetAddressIsReachable.checkAddressReachable(routeInfo.getIp(), routeInfo.getCimServerPort(), 1000);
if (!reachable) {
- log.error("ip={}, port={} are not available", routeInfo.getIp(), routeInfo.getCimServerPort());
-
- // rebuild cache
- serverCache.rebuildCacheList();
-
- throw new CIMException(StatusEnum.SERVER_NOT_AVAILABLE) ;
+ log.error("ip={}, port={} are not available, remove it.", routeInfo.getIp(), routeInfo.getCimServerPort());
+ List list = routeHandle.removeExpireServer(routeInfo);
+ String routeServer = routeHandle.routeServer(list, userId);
+ log.info("Reselect new server:[{}]", routeServer);
+ return RouteInfoParseUtil.parse(routeServer);
}
-
+ return routeInfo;
}
}
diff --git a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/UserInfoCacheService.java b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/UserInfoCacheService.java
index 1e11619d..a0c57a42 100644
--- a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/UserInfoCacheService.java
+++ b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/UserInfoCacheService.java
@@ -2,6 +2,7 @@
import com.crossoverjie.cim.common.pojo.CIMUserInfo;
+import java.util.Optional;
import java.util.Set;
/**
@@ -19,7 +20,7 @@ public interface UserInfoCacheService {
* @return
* @throws Exception
*/
- CIMUserInfo loadUserInfoByUserId(Long userId) ;
+ Optional loadUserInfoByUserId(Long userId) ;
/**
* 保存和检查用户登录情况
@@ -29,14 +30,6 @@ public interface UserInfoCacheService {
*/
boolean saveAndCheckUserLoginStatus(Long userId) throws Exception ;
- /**
- * 清除用户的登录状态
- * @param userId
- * @throws Exception
- */
- void removeLoginStatus(Long userId) throws Exception ;
-
-
/**
* query all online user
* @return online user
diff --git a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java
index ac23d2fb..d62548d3 100644
--- a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java
+++ b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImpl.java
@@ -1,35 +1,43 @@
package com.crossoverjie.cim.route.service.impl;
-import com.crossoverjie.cim.common.core.proxy.ProxyManager;
+import com.crossoverjie.cim.common.constant.Constants;
+import com.crossoverjie.cim.common.core.proxy.RpcProxyManager;
import com.crossoverjie.cim.common.enums.StatusEnum;
import com.crossoverjie.cim.common.exception.CIMException;
import com.crossoverjie.cim.common.pojo.CIMUserInfo;
+import com.crossoverjie.cim.common.pojo.RouteInfo;
import com.crossoverjie.cim.common.util.RouteInfoParseUtil;
import com.crossoverjie.cim.route.api.vo.req.ChatReqVO;
import com.crossoverjie.cim.route.api.vo.req.LoginReqVO;
import com.crossoverjie.cim.route.api.vo.res.CIMServerResVO;
import com.crossoverjie.cim.route.api.vo.res.RegisterInfoResVO;
+import com.crossoverjie.cim.route.constant.Constant;
import com.crossoverjie.cim.route.service.AccountService;
import com.crossoverjie.cim.route.service.UserInfoCacheService;
import com.crossoverjie.cim.server.api.ServerApi;
import com.crossoverjie.cim.server.api.vo.req.SendMsgReqVO;
+import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
+import org.springframework.data.redis.core.script.DefaultRedisScript;
+import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
import static com.crossoverjie.cim.common.enums.StatusEnum.OFF_LINE;
-import static com.crossoverjie.cim.route.constant.Constant.ACCOUNT_PREFIX;
-import static com.crossoverjie.cim.route.constant.Constant.ROUTE_PREFIX;
+import static com.crossoverjie.cim.route.constant.Constant.*;
/**
* Function:
@@ -42,14 +50,14 @@
@Service
public class AccountServiceRedisImpl implements AccountService {
- @Autowired
+ @Resource
private RedisTemplate redisTemplate;
- @Autowired
+ @Resource
private UserInfoCacheService userInfoCacheService;
- @Autowired
- private OkHttpClient okHttpClient;
+ @Resource
+ private ServerApi serverApi;
@Override
public RegisterInfoResVO register(RegisterInfoResVO info) {
@@ -84,7 +92,7 @@ public StatusEnum login(LoginReqVO loginReqVO) throws Exception {
//登录成功,保存登录状态
boolean status = userInfoCacheService.saveAndCheckUserLoginStatus(loginReqVO.getUserId());
- if (status == false) {
+ if (!status) {
//重复登录
return StatusEnum.REPEAT_LOGIN;
}
@@ -130,44 +138,48 @@ public CIMServerResVO loadRouteRelatedByUserId(Long userId) {
throw new CIMException(OFF_LINE);
}
- CIMServerResVO cimServerResVO = new CIMServerResVO(RouteInfoParseUtil.parse(value));
+ RouteInfo parse = RouteInfoParseUtil.parse(value);
+ CIMServerResVO cimServerResVO =
+ new CIMServerResVO(parse.getIp(), parse.getCimServerPort(), parse.getHttpPort());
return cimServerResVO;
}
private void parseServerInfo(Map routes, String key) {
long userId = Long.valueOf(key.split(":")[1]);
String value = redisTemplate.opsForValue().get(key);
- CIMServerResVO cimServerResVO = new CIMServerResVO(RouteInfoParseUtil.parse(value));
+ RouteInfo parse = RouteInfoParseUtil.parse(value);
+ CIMServerResVO cimServerResVO =
+ new CIMServerResVO(parse.getIp(), parse.getCimServerPort(), parse.getHttpPort());
routes.put(userId, cimServerResVO);
}
@Override
- public void pushMsg(CIMServerResVO cimServerResVO, long sendUserId, ChatReqVO groupReqVO) throws Exception {
- CIMUserInfo cimUserInfo = userInfoCacheService.loadUserInfoByUserId(sendUserId);
-
- String url = "http://" + cimServerResVO.getIp() + ":" + cimServerResVO.getHttpPort();
- ServerApi serverApi = new ProxyManager<>(ServerApi.class, url, okHttpClient).getInstance();
- SendMsgReqVO vo = new SendMsgReqVO(cimUserInfo.getUserName() + ":" + groupReqVO.getMsg(), groupReqVO.getUserId());
- Response response = null;
- try {
- response = (Response) serverApi.sendMsg(vo);
- } catch (Exception e) {
- log.error("Exception", e);
- } finally {
- response.body().close();
- }
+ public void pushMsg(CIMServerResVO cimServerResVO, long sendUserId, ChatReqVO groupReqVO) {
+ Optional cimUserInfo = userInfoCacheService.loadUserInfoByUserId(sendUserId);
+
+ cimUserInfo.ifPresent(userInfo -> {
+ String url = "http://" + cimServerResVO.getIp() + ":" + cimServerResVO.getHttpPort();
+ SendMsgReqVO vo =
+ new SendMsgReqVO(groupReqVO.getMsg(), groupReqVO.getUserId());
+ vo.setProperties(Map.of(
+ Constants.MetaKey.USER_ID, String.valueOf(sendUserId),
+ Constants.MetaKey.USER_NAME, userInfo.getUserName())
+ );
+ serverApi.sendMsg(vo, url);
+
+ });
}
@Override
- public void offLine(Long userId) throws Exception {
-
- // TODO: 2019-01-21 改为一个原子命令,以防数据一致性
+ public void offLine(Long userId) {
- //删除路由
- redisTemplate.delete(ROUTE_PREFIX + userId);
+ DefaultRedisScript redisScript = new DefaultRedisScript();
+ redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/offLine.lua")));
- //删除登录状态
- userInfoCacheService.removeLoginStatus(userId);
+ redisTemplate.execute(redisScript,
+ Collections.singletonList(ROUTE_PREFIX + userId),
+ LOGIN_STATUS_PREFIX,
+ userId.toString());
}
}
diff --git a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/UserInfoCacheServiceImpl.java b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/UserInfoCacheServiceImpl.java
index 87025534..336afb32 100644
--- a/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/UserInfoCacheServiceImpl.java
+++ b/cim-forward-route/src/main/java/com/crossoverjie/cim/route/service/impl/UserInfoCacheServiceImpl.java
@@ -2,14 +2,21 @@
import com.crossoverjie.cim.common.pojo.CIMUserInfo;
import com.crossoverjie.cim.route.service.UserInfoCacheService;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
import static com.crossoverjie.cim.route.constant.Constant.ACCOUNT_PREFIX;
import static com.crossoverjie.cim.route.constant.Constant.LOGIN_STATUS_PREFIX;
@@ -25,31 +32,16 @@
@Service
public class UserInfoCacheServiceImpl implements UserInfoCacheService {
- /**
- * todo 本地缓存,为了防止内存撑爆,后期可换为 LRU。
- */
- private final static Map USER_INFO_MAP = new ConcurrentHashMap<>(64) ;
-
@Autowired
private RedisTemplate redisTemplate ;
- @Override
- public CIMUserInfo loadUserInfoByUserId(Long userId) {
-
- //优先从本地缓存获取
- CIMUserInfo cimUserInfo = USER_INFO_MAP.get(userId);
- if (cimUserInfo != null){
- return cimUserInfo ;
- }
-
- //load redis
- String sendUserName = redisTemplate.opsForValue().get(ACCOUNT_PREFIX + userId);
- if (sendUserName != null){
- cimUserInfo = new CIMUserInfo(userId,sendUserName) ;
- USER_INFO_MAP.put(userId,cimUserInfo) ;
- }
+ @Resource(name = "userInfoCache")
+ private LoadingCache> userInfoMap;
- return cimUserInfo;
+ @Override
+ public Optional loadUserInfoByUserId(Long userId) {
+ //Retrieve user information using a second-level cache.
+ return userInfoMap.getUnchecked(userId);
}
@Override
@@ -63,11 +55,6 @@ public boolean saveAndCheckUserLoginStatus(Long userId) throws Exception {
}
}
- @Override
- public void removeLoginStatus(Long userId) throws Exception {
- redisTemplate.opsForSet().remove(LOGIN_STATUS_PREFIX,userId.toString()) ;
- }
-
@Override
public Set onlineUser() {
Set set = null ;
@@ -76,8 +63,9 @@ public Set onlineUser() {
if (set == null){
set = new HashSet<>(64) ;
}
- CIMUserInfo cimUserInfo = loadUserInfoByUserId(Long.valueOf(member)) ;
- set.add(cimUserInfo) ;
+ Optional cimUserInfo = loadUserInfoByUserId(Long.valueOf(member)) ;
+
+ cimUserInfo.ifPresent(set::add);
}
return set;
diff --git a/cim-forward-route/src/main/resources/banner.txt b/cim-forward-route/src/main/resources/banner.txt
index 97b15b91..165abd2e 100644
--- a/cim-forward-route/src/main/resources/banner.txt
+++ b/cim-forward-route/src/main/resources/banner.txt
@@ -1,14 +1,7 @@
-
- ▄████▄ ██▓ ███▄ ▄███▓
-▒██▀ ▀█ ▓██▒▓██▒▀█▀ ██▒
-▒▓█ ▄ ▒██▒▓██ ▓██░
-▒▓▓▄ ▄██▒░██░▒██ ▒██
-▒ ▓███▀ ░░██░▒██▒ ░██▒
-░ ░▒ ▒ ░░▓ ░ ▒░ ░ ░
- ░ ▒ ▒ ░░ ░ ░
-░ ▒ ░░ ░
-░ ░ ░ ░
-░
+ _ __
+ ____(_)_ _ _______ __ __/ /____
+/ __/ / ' \ / __/ _ \/ // / __/ -_)
+\__/_/_/_/_/ /_/ \___/\_,_/\__/\__/
Power by @crossoverJie
diff --git a/cim-forward-route/src/main/resources/lua/offLine.lua b/cim-forward-route/src/main/resources/lua/offLine.lua
new file mode 100644
index 00000000..7fc5d82a
--- /dev/null
+++ b/cim-forward-route/src/main/resources/lua/offLine.lua
@@ -0,0 +1,5 @@
+
+redis.call('DEL', KEYS[1])
+
+redis.call('SREM', ARGV[1], ARGV[2])
+
diff --git a/cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/AbstractBaseTest.java b/cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/AbstractBaseTest.java
new file mode 100644
index 00000000..350cd589
--- /dev/null
+++ b/cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/AbstractBaseTest.java
@@ -0,0 +1,46 @@
+package com.crossoverjie.cim.route.service.impl;
+
+import com.clevercloud.testcontainers.zookeeper.ZooKeeperContainer;
+import com.redis.testcontainers.RedisContainer;
+import java.time.Duration;
+import java.util.List;
+import org.junit.After;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.utility.DockerImageName;
+
+public class AbstractBaseTest {
+
+ @Container
+ static RedisContainer redis = new RedisContainer(DockerImageName.parse("redis:7.4.0"));
+
+ private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName
+ .parse("zookeeper")
+ .withTag("3.9.2");
+
+ private static final Duration DEFAULT_STARTUP_TIMEOUT = Duration.ofSeconds(60);
+
+ @Container
+ static final ZooKeeperContainer
+ zooKeeperContainer = new ZooKeeperContainer(DEFAULT_IMAGE_NAME, DEFAULT_STARTUP_TIMEOUT);
+
+
+ @BeforeAll
+ public static void before(){
+ redis.setExposedPorts(List.of(6379));
+ redis.setPortBindings(List.of("6379:6379"));
+ redis.start();
+
+ zooKeeperContainer.setExposedPorts(List.of(2181));
+ zooKeeperContainer.setPortBindings(List.of("2181:2181"));
+ zooKeeperContainer.start();
+ }
+
+ @AfterAll
+ public static void after(){
+ redis.stop();
+ zooKeeperContainer.stop();
+ }
+
+}
diff --git a/cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImplTest.java b/cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImplTest.java
index ef43b38e..5046d8df 100644
--- a/cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImplTest.java
+++ b/cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/AccountServiceRedisImplTest.java
@@ -4,20 +4,15 @@
import com.crossoverjie.cim.route.RouteApplication;
import com.crossoverjie.cim.route.api.vo.res.CIMServerResVO;
import com.crossoverjie.cim.route.service.AccountService;
+import java.util.Map;
import lombok.extern.slf4j.Slf4j;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
@Slf4j
@SpringBootTest(classes = RouteApplication.class)
-@RunWith(SpringRunner.class)
-public class AccountServiceRedisImplTest {
+public class AccountServiceRedisImplTest extends AbstractBaseTest{
@Autowired
private AccountService accountService ;
@@ -29,7 +24,6 @@ public void loadRouteRelated() throws Exception {
Map longCIMServerResVOMap = accountService.loadRouteRelated();
log.info("longCIMServerResVOMap={},cun={}" , JSON.toJSONString(longCIMServerResVOMap),i);
}
- TimeUnit.SECONDS.sleep(10);
}
}
\ No newline at end of file
diff --git a/cim-forward-route/src/test/java/RedisTest.java b/cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/RedisTest.java
similarity index 62%
rename from cim-forward-route/src/test/java/RedisTest.java
rename to cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/RedisTest.java
index 63b1b05b..2b437438 100644
--- a/cim-forward-route/src/test/java/RedisTest.java
+++ b/cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/RedisTest.java
@@ -1,21 +1,15 @@
+package com.crossoverjie.cim.route.service.impl;
+
import com.crossoverjie.cim.route.RouteApplication;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.test.context.junit4.SpringRunner;
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2018/12/23 21:40
- * @since JDK 1.8
- */
+
@SpringBootTest(classes = RouteApplication.class)
-@RunWith(SpringRunner.class)
-public class RedisTest {
+public class RedisTest extends AbstractBaseTest {
@Autowired
private RedisTemplate redisTemplate ;
@@ -24,6 +18,6 @@ public class RedisTest {
public void test(){
redisTemplate.opsForValue().set("test","test") ;
String test = redisTemplate.opsForValue().get("test");
- System.out.println("====" + test);
+ Assertions.assertEquals("test",test);
}
}
diff --git a/cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/UserInfoCacheServiceImplTest.java b/cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/UserInfoCacheServiceImplTest.java
index b71ea2ef..51865314 100644
--- a/cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/UserInfoCacheServiceImplTest.java
+++ b/cim-forward-route/src/test/java/com/crossoverjie/cim/route/service/impl/UserInfoCacheServiceImplTest.java
@@ -4,19 +4,15 @@
import com.crossoverjie.cim.common.pojo.CIMUserInfo;
import com.crossoverjie.cim.route.RouteApplication;
import com.crossoverjie.cim.route.service.UserInfoCacheService;
+import java.util.Set;
import lombok.extern.slf4j.Slf4j;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import java.util.Set;
@Slf4j
@SpringBootTest(classes = RouteApplication.class)
-@RunWith(SpringRunner.class)
-public class UserInfoCacheServiceImplTest {
+public class UserInfoCacheServiceImplTest extends AbstractBaseTest{
@Autowired
private UserInfoCacheService userInfoCacheService;
@@ -27,11 +23,6 @@ public void checkUserLoginStatus() throws Exception {
log.info("status={}", status);
}
- @Test
- public void removeLoginStatus() throws Exception {
- userInfoCacheService.removeLoginStatus(2000L);
- }
-
@Test
public void onlineUser(){
Set cimUserInfos = userInfoCacheService.onlineUser();
diff --git a/cim-forward-route/src/test/resources/application.yaml b/cim-forward-route/src/test/resources/application.yaml
new file mode 100644
index 00000000..f2007e1d
--- /dev/null
+++ b/cim-forward-route/src/test/resources/application.yaml
@@ -0,0 +1,49 @@
+spring:
+ application:
+ name: cim-forward-route
+ data:
+ redis:
+ host: 127.0.0.1
+ port: 6379
+ jedis:
+ pool:
+ max-active: 100
+ max-idle: 100
+ max-wait: 1000
+ min-idle: 10
+# web port
+server:
+ port: 8083
+
+logging:
+ level:
+ root: info
+
+ # enable swagger
+springdoc:
+ swagger-ui:
+ enabled: true
+
+app:
+ zk:
+ addr: 127.0.0.1:2181
+ connect:
+ timeout: 30000
+ root: /route
+
+ # route strategy
+ #app.route.way=com.crossoverjie.cim.common.route.algorithm.loop.LoopHandle
+
+ # route strategy
+ #app.route.way=com.crossoverjie.cim.common.route.algorithm.random.RandomHandle
+
+ # route strategy
+ route:
+ way:
+ handler: com.crossoverjie.cim.common.route.algorithm.consistenthash.ConsistentHashHandle
+
+ #app.route.way.consitenthash=com.crossoverjie.cim.common.route.algorithm.consistenthash.SortArrayMapConsistentHash
+
+ consitenthash: com.crossoverjie.cim.common.route.algorithm.consistenthash.TreeMapConsistentHash
+
+
diff --git a/cim-integration-test/pom.xml b/cim-integration-test/pom.xml
new file mode 100644
index 00000000..cdd5f4f9
--- /dev/null
+++ b/cim-integration-test/pom.xml
@@ -0,0 +1,78 @@
+
+
+ 4.0.0
+
+ com.crossoverjie.netty
+ cim
+ 1.0.0-SNAPSHOT
+
+
+ cim-integration-test
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+ com.crossoverjie.netty
+ cim-server
+ ${project.version}
+ compile
+
+
+
+ com.crossoverjie.netty
+ cim-forward-route
+ ${project.version}
+ compile
+
+
+
+ org.junit.vintage
+ junit-vintage-engine
+ test
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+
+ org.testcontainers
+ testcontainers
+ compile
+
+
+ org.testcontainers
+ junit-jupiter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ compile
+
+
+
+ com.clever-cloud
+ testcontainers-zookeeper
+ compile
+
+
+
+ com.redis
+ testcontainers-redis
+ compile
+
+
+
+
+
\ No newline at end of file
diff --git a/cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/route/AbstractRouteBaseTest.java b/cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/route/AbstractRouteBaseTest.java
new file mode 100644
index 00000000..8f025507
--- /dev/null
+++ b/cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/route/AbstractRouteBaseTest.java
@@ -0,0 +1,48 @@
+package com.crossoverjie.cim.client.sdk.route;
+
+import com.crossoverjie.cim.common.res.BaseResponse;
+import com.crossoverjie.cim.client.sdk.server.AbstractServerBaseTest;
+import com.crossoverjie.cim.route.RouteApplication;
+import com.crossoverjie.cim.route.api.RouteApi;
+import com.crossoverjie.cim.route.api.vo.req.RegisterInfoReqVO;
+import com.crossoverjie.cim.route.api.vo.res.RegisterInfoResVO;
+import com.redis.testcontainers.RedisContainer;
+import org.springframework.boot.SpringApplication;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.utility.DockerImageName;
+
+public abstract class AbstractRouteBaseTest extends AbstractServerBaseTest {
+
+ @Container
+ RedisContainer redis = new RedisContainer(DockerImageName.parse("redis:7.4.0"));
+
+ private ConfigurableApplicationContext run;
+ public void startRoute() {
+ redis.start();
+ SpringApplication route = new SpringApplication(RouteApplication.class);
+ String[] args = new String[]{
+ "--spring.data.redis.host=" + redis.getHost(),
+ "--spring.data.redis.port=" + redis.getMappedPort(6379),
+ "--app.zk.addr=" + super.getZookeeperAddr(),
+ };
+ route.setAdditionalProfiles("route");
+ run = route.run(args);
+ }
+
+ public void close(){
+ super.close();
+ redis.close();
+ run.close();
+ }
+
+ public Long registerAccount(String userName) throws Exception {
+ // register user
+ RouteApi routeApi = com.crossoverjie.cim.route.util.SpringBeanFactory.getBean(RouteApi.class);
+ RegisterInfoReqVO reqVO = new RegisterInfoReqVO();
+ reqVO.setUserName(userName);
+ BaseResponse account =
+ routeApi.registerAccount(reqVO);
+ return account.getDataBody().getUserId();
+ }
+}
\ No newline at end of file
diff --git a/cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/server/AbstractServerBaseTest.java b/cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/server/AbstractServerBaseTest.java
new file mode 100644
index 00000000..d274d498
--- /dev/null
+++ b/cim-integration-test/src/main/java/com/crossoverjie/cim/client/sdk/server/AbstractServerBaseTest.java
@@ -0,0 +1,77 @@
+package com.crossoverjie.cim.client.sdk.server;
+
+import com.clevercloud.testcontainers.zookeeper.ZooKeeperContainer;
+import com.crossoverjie.cim.server.CIMServerApplication;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+import lombok.Getter;
+import org.springframework.boot.SpringApplication;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.utility.DockerImageName;
+
+public abstract class AbstractServerBaseTest {
+ private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName
+ .parse("zookeeper")
+ .withTag("3.9.2");
+
+ private static final Duration DEFAULT_STARTUP_TIMEOUT = Duration.ofSeconds(60);
+
+ @Container
+ public final ZooKeeperContainer
+ zooKeeperContainer = new ZooKeeperContainer(DEFAULT_IMAGE_NAME, DEFAULT_STARTUP_TIMEOUT);
+
+ @Getter
+ private String zookeeperAddr;
+
+ private ConfigurableApplicationContext singleRun;
+ public void starSingleServer() {
+ zooKeeperContainer.start();
+ zookeeperAddr = String.format("%s:%d", zooKeeperContainer.getHost(), zooKeeperContainer.getMappedPort(ZooKeeperContainer.DEFAULT_CLIENT_PORT));
+ SpringApplication server = new SpringApplication(CIMServerApplication.class);
+ singleRun = server.run("--app.zk.addr=" + zookeeperAddr);
+ }
+ public void stopSingle(){
+ singleRun.close();
+ }
+
+ private final Map runMap = new HashMap<>(2);
+ public void startTwoServer() {
+ if (!zooKeeperContainer.isRunning()){
+ zooKeeperContainer.start();
+ }
+ zookeeperAddr = String.format("%s:%d", zooKeeperContainer.getHost(), zooKeeperContainer.getMappedPort(ZooKeeperContainer.DEFAULT_CLIENT_PORT));
+ SpringApplication server = new SpringApplication(CIMServerApplication.class);
+ String[] args1 = new String[]{
+ "--cim.server.port=11211",
+ "--server.port=8081",
+ "--app.zk.addr=" + zookeeperAddr,
+ };
+ ConfigurableApplicationContext run1 = server.run(args1);
+ runMap.put(Integer.parseInt("11211"), run1);
+
+
+ SpringApplication server2 = new SpringApplication(CIMServerApplication.class);
+ String[] args2 = new String[]{
+ "--cim.server.port=11212",
+ "--server.port=8082",
+ "--app.zk.addr=" + zookeeperAddr,
+ };
+ ConfigurableApplicationContext run2 = server2.run(args2);
+ runMap.put(Integer.parseInt("11212"), run2);
+ }
+
+ public void stopServer(Integer port) {
+ runMap.get(port).close();
+ runMap.remove(port);
+ }
+ public void stopTwoServer() {
+ runMap.forEach((k,v) -> v.close());
+ }
+
+ public void close(){
+ zooKeeperContainer.close();
+ }
+
+}
diff --git a/cim-integration-test/src/test/resources/application-client.yaml b/cim-integration-test/src/test/resources/application-client.yaml
new file mode 100644
index 00000000..8131eef9
--- /dev/null
+++ b/cim-integration-test/src/test/resources/application-client.yaml
@@ -0,0 +1,37 @@
+spring:
+ application:
+ name: cim-client
+
+# web port
+server:
+ port: 8082
+
+logging:
+ level:
+ root: error
+
+# enable swagger
+springdoc:
+ swagger-ui:
+ enabled: true
+
+# log path
+cim:
+ msg:
+ logger:
+ path: /opt/logs/cim/
+ route:
+ url: http://localhost:8083 # route url suggested that this is Nginx address
+ user: # cim userId and userName
+ id: 1722343979085
+ userName: zhangsan
+ callback:
+ thread:
+ queue:
+ size: 2
+ pool:
+ size: 2
+ heartbeat:
+ time: 60 # cim heartbeat time (seconds)
+ reconnect:
+ count: 3
\ No newline at end of file
diff --git a/cim-integration-test/src/test/resources/application-route.yaml b/cim-integration-test/src/test/resources/application-route.yaml
new file mode 100644
index 00000000..bfd1a5f0
--- /dev/null
+++ b/cim-integration-test/src/test/resources/application-route.yaml
@@ -0,0 +1,49 @@
+spring:
+ application:
+ name:
+ cim-forward-route
+ data:
+ redis:
+ host: 127.0.0.1
+ port: 6379
+ jedis:
+ pool:
+ max-active: 100
+ max-idle: 100
+ max-wait: 1000
+ min-idle: 10
+# web port
+server:
+ port: 8083
+
+logging:
+ level:
+ root: info
+
+ # enable swagger
+springdoc:
+ swagger-ui:
+ enabled: true
+
+app:
+ zk:
+ connect:
+ timeout: 30000
+ root: /route
+
+ # route strategy
+ #app.route.way=com.crossoverjie.cim.common.route.algorithm.loop.LoopHandle
+
+ # route strategy
+ #app.route.way=com.crossoverjie.cim.common.route.algorithm.random.RandomHandle
+
+ # route strategy
+ route:
+ way:
+ handler: com.crossoverjie.cim.common.route.algorithm.consistenthash.ConsistentHashHandle
+
+ #app.route.way.consitenthash=com.crossoverjie.cim.common.route.algorithm.consistenthash.SortArrayMapConsistentHash
+
+ consitenthash: com.crossoverjie.cim.common.route.algorithm.consistenthash.TreeMapConsistentHash
+
+
diff --git a/cim-rout-api/pom.xml b/cim-rout-api/pom.xml
index a1164fed..efe9f7b2 100644
--- a/cim-rout-api/pom.xml
+++ b/cim-rout-api/pom.xml
@@ -10,7 +10,7 @@
4.0.0
cim-rout-api
- 1.0.1-SNAPSHOT
+ 1.0.0-SNAPSHOT
diff --git a/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/RouteApi.java b/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/RouteApi.java
index 90b65c3d..7c5fd05b 100644
--- a/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/RouteApi.java
+++ b/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/RouteApi.java
@@ -1,11 +1,16 @@
package com.crossoverjie.cim.route.api;
+import com.crossoverjie.cim.common.core.proxy.Request;
+import com.crossoverjie.cim.common.pojo.CIMUserInfo;
import com.crossoverjie.cim.common.res.BaseResponse;
+import com.crossoverjie.cim.common.res.NULLBody;
import com.crossoverjie.cim.route.api.vo.req.ChatReqVO;
import com.crossoverjie.cim.route.api.vo.req.LoginReqVO;
import com.crossoverjie.cim.route.api.vo.req.P2PReqVO;
import com.crossoverjie.cim.route.api.vo.req.RegisterInfoReqVO;
+import com.crossoverjie.cim.route.api.vo.res.CIMServerResVO;
import com.crossoverjie.cim.route.api.vo.res.RegisterInfoResVO;
+import java.util.Set;
/**
* Function: Route Api
@@ -23,7 +28,7 @@ public interface RouteApi {
* @return
* @throws Exception
*/
- Object groupRoute(ChatReqVO groupReqVO) throws Exception;
+ BaseResponse groupRoute(ChatReqVO groupReqVO);
/**
* Point to point chat
@@ -31,7 +36,7 @@ public interface RouteApi {
* @return
* @throws Exception
*/
- Object p2pRoute(P2PReqVO p2pRequest) throws Exception;
+ BaseResponse p2pRoute(P2PReqVO p2pRequest);
/**
@@ -41,7 +46,7 @@ public interface RouteApi {
* @return
* @throws Exception
*/
- Object offLine(ChatReqVO groupReqVO) throws Exception;
+ BaseResponse offLine(ChatReqVO groupReqVO);
/**
* Login account
@@ -49,7 +54,7 @@ public interface RouteApi {
* @return
* @throws Exception
*/
- Object login(LoginReqVO loginReqVO) throws Exception;
+ BaseResponse login(LoginReqVO loginReqVO) throws Exception;
/**
* Register account
@@ -66,5 +71,8 @@ public interface RouteApi {
* @return
* @throws Exception
*/
- Object onlineUser() throws Exception;
+ @Request(method = Request.GET)
+ BaseResponse> onlineUser() throws Exception;
+
+ // TODO: 2024/8/19 Get cache server & metastore server
}
diff --git a/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/ChatReqVO.java b/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/ChatReqVO.java
index 10c6a682..53b2a01b 100644
--- a/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/ChatReqVO.java
+++ b/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/ChatReqVO.java
@@ -4,6 +4,10 @@
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
/**
* Function: Google Protocol 编解码发送
@@ -12,6 +16,10 @@
* Date: 2018/05/21 15:56
* @since JDK 1.8
*/
+@EqualsAndHashCode(callSuper = true)
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
public class ChatReqVO extends BaseRequest {
@NotNull(message = "userId 不能为空")
@@ -23,29 +31,6 @@ public class ChatReqVO extends BaseRequest {
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "msg", example = "hello")
private String msg ;
- public ChatReqVO() {
- }
-
- public ChatReqVO(Long userId, String msg) {
- this.userId = userId;
- this.msg = msg;
- }
-
- public String getMsg() {
- return msg;
- }
-
- public void setMsg(String msg) {
- this.msg = msg;
- }
-
- public Long getUserId() {
- return userId;
- }
-
- public void setUserId(Long userId) {
- this.userId = userId;
- }
@Override
public String toString() {
diff --git a/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/LoginReqVO.java b/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/LoginReqVO.java
index fcd97d8f..8e810d80 100644
--- a/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/LoginReqVO.java
+++ b/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/LoginReqVO.java
@@ -1,6 +1,7 @@
package com.crossoverjie.cim.route.api.vo.req;
import com.crossoverjie.cim.common.req.BaseRequest;
+import lombok.AllArgsConstructor;
/**
* Function:
@@ -9,6 +10,7 @@
* Date: 2018/12/23 22:30
* @since JDK 1.8
*/
+@AllArgsConstructor
public class LoginReqVO extends BaseRequest{
private Long userId ;
private String userName ;
diff --git a/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/P2PReqVO.java b/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/P2PReqVO.java
index d0d0c62c..98a615fd 100644
--- a/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/P2PReqVO.java
+++ b/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/P2PReqVO.java
@@ -4,29 +4,31 @@
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
+import lombok.Builder;
/**
- * Function: 单聊请求
+ * Function: P2P request
*
* @author crossoverJie
* Date: 2018/05/21 15:56
* @since JDK 1.8
*/
+@Builder
public class P2PReqVO extends BaseRequest {
- @NotNull(message = "userId 不能为空")
- @Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "消息发送者的 userId", example = "1545574049323")
+ @NotNull(message = "userId can't be null")
+ @Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "current send userId", example = "1545574049323")
private Long userId ;
- @NotNull(message = "userId 不能为空")
- @Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "消息接收者的 userId", example = "1545574049323")
+ @NotNull(message = "userId can't be null")
+ @Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "message received userId", example = "1545574049323")
private Long receiveUserId ;
- @NotNull(message = "msg 不能为空")
+ @NotNull(message = "msg can't be null")
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "msg", example = "hello")
private String msg ;
diff --git a/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/RegisterInfoReqVO.java b/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/RegisterInfoReqVO.java
index 6417e3ff..712a5e25 100644
--- a/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/RegisterInfoReqVO.java
+++ b/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/req/RegisterInfoReqVO.java
@@ -4,6 +4,8 @@
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
+import lombok.Builder;
+import lombok.Data;
/**
* Function:
diff --git a/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/res/CIMServerResVO.java b/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/res/CIMServerResVO.java
index cec52bfb..07911f84 100644
--- a/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/res/CIMServerResVO.java
+++ b/cim-rout-api/src/main/java/com/crossoverjie/cim/route/api/vo/res/CIMServerResVO.java
@@ -3,6 +3,9 @@
import com.crossoverjie.cim.common.pojo.RouteInfo;
import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
/**
* Function:
@@ -11,39 +14,13 @@
* Date: 2018/12/23 00:43
* @since JDK 1.8
*/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
public class CIMServerResVO implements Serializable {
private String ip ;
private Integer cimServerPort;
private Integer httpPort;
- public CIMServerResVO(RouteInfo routeInfo) {
- this.ip = routeInfo.getIp();
- this.cimServerPort = routeInfo.getCimServerPort();
- this.httpPort = routeInfo.getHttpPort();
- }
-
- public String getIp() {
- return ip;
- }
-
- public void setIp(String ip) {
- this.ip = ip;
- }
-
- public Integer getCimServerPort() {
- return cimServerPort;
- }
-
- public void setCimServerPort(Integer cimServerPort) {
- this.cimServerPort = cimServerPort;
- }
-
- public Integer getHttpPort() {
- return httpPort;
- }
-
- public void setHttpPort(Integer httpPort) {
- this.httpPort = httpPort;
- }
}
diff --git a/cim-server-api/pom.xml b/cim-server-api/pom.xml
index 57897840..634775a9 100644
--- a/cim-server-api/pom.xml
+++ b/cim-server-api/pom.xml
@@ -10,7 +10,7 @@
4.0.0
cim-server-api
- 1.0.1-SNAPSHOT
+ 1.0.0-SNAPSHOT
diff --git a/cim-server-api/src/main/java/com/crossoverjie/cim/server/api/ServerApi.java b/cim-server-api/src/main/java/com/crossoverjie/cim/server/api/ServerApi.java
index 9e1be26e..15e83ecc 100644
--- a/cim-server-api/src/main/java/com/crossoverjie/cim/server/api/ServerApi.java
+++ b/cim-server-api/src/main/java/com/crossoverjie/cim/server/api/ServerApi.java
@@ -1,6 +1,9 @@
package com.crossoverjie.cim.server.api;
+import com.crossoverjie.cim.common.core.proxy.DynamicUrl;
+import com.crossoverjie.cim.common.res.BaseResponse;
import com.crossoverjie.cim.server.api.vo.req.SendMsgReqVO;
+import com.crossoverjie.cim.server.api.vo.res.SendMsgResVO;
/**
* Function:
@@ -17,5 +20,5 @@ public interface ServerApi {
* @return
* @throws Exception
*/
- Object sendMsg(SendMsgReqVO sendMsgReqVO) throws Exception;
+ BaseResponse sendMsg(SendMsgReqVO sendMsgReqVO, @DynamicUrl String url);
}
diff --git a/cim-server-api/src/main/java/com/crossoverjie/cim/server/api/vo/req/SendMsgReqVO.java b/cim-server-api/src/main/java/com/crossoverjie/cim/server/api/vo/req/SendMsgReqVO.java
index 247d49f4..730588b2 100644
--- a/cim-server-api/src/main/java/com/crossoverjie/cim/server/api/vo/req/SendMsgReqVO.java
+++ b/cim-server-api/src/main/java/com/crossoverjie/cim/server/api/vo/req/SendMsgReqVO.java
@@ -4,6 +4,9 @@
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
+import java.util.Map;
+import lombok.Getter;
+import lombok.Setter;
/**
* Function:
@@ -22,6 +25,10 @@ public class SendMsgReqVO extends BaseRequest {
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "userId", example = "11")
private Long userId ;
+ @Setter
+ @Getter
+ private Map properties;
+
public SendMsgReqVO() {
}
diff --git a/cim-server/pom.xml b/cim-server/pom.xml
index de73ab52..43e5cab5 100644
--- a/cim-server/pom.xml
+++ b/cim-server/pom.xml
@@ -88,21 +88,5 @@
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
- repackage
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cim-server/src/main/java/com/crossoverjie/cim/server/CIMServerApplication.java b/cim-server/src/main/java/com/crossoverjie/cim/server/CIMServerApplication.java
index cce3513f..a5f99505 100644
--- a/cim-server/src/main/java/com/crossoverjie/cim/server/CIMServerApplication.java
+++ b/cim-server/src/main/java/com/crossoverjie/cim/server/CIMServerApplication.java
@@ -1,9 +1,10 @@
package com.crossoverjie.cim.server;
+import com.crossoverjie.cim.common.metastore.MetaStore;
import com.crossoverjie.cim.server.config.AppConfiguration;
-import com.crossoverjie.cim.server.kit.RegistryZK;
+import com.crossoverjie.cim.server.kit.RegistryMetaStore;
+import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
@@ -19,9 +20,12 @@
public class CIMServerApplication implements CommandLineRunner{
- @Autowired
+ @Resource
private AppConfiguration appConfiguration ;
+ @Resource
+ private MetaStore metaStore;
+
@Value("${server.port}")
private int httpPort ;
@@ -32,9 +36,8 @@ public static void main(String[] args) {
@Override
public void run(String... args) throws Exception {
- //获得本机IP
String addr = InetAddress.getLocalHost().getHostAddress();
- Thread thread = new Thread(new RegistryZK(addr, appConfiguration.getCimServerPort(),httpPort));
+ Thread thread = new Thread(new RegistryMetaStore(metaStore, addr, appConfiguration.getCimServerPort(),httpPort));
thread.setName("registry-zk");
thread.start() ;
}
diff --git a/cim-server/src/main/java/com/crossoverjie/cim/server/config/BeanConfig.java b/cim-server/src/main/java/com/crossoverjie/cim/server/config/BeanConfig.java
index 81c6f11b..f73bc49f 100644
--- a/cim-server/src/main/java/com/crossoverjie/cim/server/config/BeanConfig.java
+++ b/cim-server/src/main/java/com/crossoverjie/cim/server/config/BeanConfig.java
@@ -1,15 +1,17 @@
package com.crossoverjie.cim.server.config;
-import com.crossoverjie.cim.common.constant.Constants;
-import com.crossoverjie.cim.common.protocol.CIMRequestProto;
+import com.crossoverjie.cim.common.core.proxy.RpcProxyManager;
+import com.crossoverjie.cim.common.metastore.MetaStore;
+import com.crossoverjie.cim.common.metastore.ZkMetaStoreImpl;
+import com.crossoverjie.cim.common.protocol.BaseCommand;
+import com.crossoverjie.cim.common.protocol.Request;
+import com.crossoverjie.cim.route.api.RouteApi;
+import jakarta.annotation.Resource;
+import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
-import org.I0Itec.zkclient.ZkClient;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import java.util.concurrent.TimeUnit;
-
/**
* Function:
*
@@ -20,13 +22,8 @@
@Configuration
public class BeanConfig {
- @Autowired
- private AppConfiguration appConfiguration ;
-
- @Bean
- public ZkClient buildZKClient(){
- return new ZkClient(appConfiguration.getZkAddr(), appConfiguration.getZkConnectTimeout());
- }
+ @Resource
+ private AppConfiguration appConfiguration;
/**
* http client
@@ -42,18 +39,27 @@ public OkHttpClient okHttpClient() {
return builder.build();
}
+ @Bean
+ public MetaStore metaStore() {
+ return new ZkMetaStoreImpl();
+ }
+
/**
* 创建心跳单例
* @return
*/
@Bean(value = "heartBeat")
- public CIMRequestProto.CIMReqProtocol heartBeat() {
- CIMRequestProto.CIMReqProtocol heart = CIMRequestProto.CIMReqProtocol.newBuilder()
+ public Request heartBeat() {
+ return Request.newBuilder()
.setRequestId(0L)
.setReqMsg("pong")
- .setType(Constants.CommandType.PING)
+ .setCmd(BaseCommand.PING)
.build();
- return heart;
+ }
+
+ @Bean
+ public RouteApi routeApi(OkHttpClient okHttpClient) {
+ return RpcProxyManager.create(RouteApi.class, appConfiguration.getRouteUrl(), okHttpClient);
}
}
diff --git a/cim-server/src/main/java/com/crossoverjie/cim/server/controller/IndexController.java b/cim-server/src/main/java/com/crossoverjie/cim/server/controller/IndexController.java
index a85b8677..748e46fa 100644
--- a/cim-server/src/main/java/com/crossoverjie/cim/server/controller/IndexController.java
+++ b/cim-server/src/main/java/com/crossoverjie/cim/server/controller/IndexController.java
@@ -1,5 +1,6 @@
package com.crossoverjie.cim.server.controller;
+import com.crossoverjie.cim.common.core.proxy.DynamicUrl;
import com.crossoverjie.cim.common.enums.StatusEnum;
import com.crossoverjie.cim.common.res.BaseResponse;
import com.crossoverjie.cim.server.api.ServerApi;
@@ -38,7 +39,7 @@ public class IndexController implements ServerApi {
@Operation(summary = "Push msg to client")
@RequestMapping(value = "sendMsg",method = RequestMethod.POST)
@ResponseBody
- public BaseResponse sendMsg(@RequestBody SendMsgReqVO sendMsgReqVO){
+ public BaseResponse sendMsg(@RequestBody SendMsgReqVO sendMsgReqVO, @DynamicUrl String url){
BaseResponse res = new BaseResponse();
cimServer.sendMsg(sendMsgReqVO) ;
diff --git a/cim-server/src/main/java/com/crossoverjie/cim/server/handle/CIMServerHandle.java b/cim-server/src/main/java/com/crossoverjie/cim/server/handle/CIMServerHandle.java
index e7e616f1..13636af0 100644
--- a/cim-server/src/main/java/com/crossoverjie/cim/server/handle/CIMServerHandle.java
+++ b/cim-server/src/main/java/com/crossoverjie/cim/server/handle/CIMServerHandle.java
@@ -1,10 +1,10 @@
package com.crossoverjie.cim.server.handle;
-import com.crossoverjie.cim.common.constant.Constants;
import com.crossoverjie.cim.common.exception.CIMException;
import com.crossoverjie.cim.common.kit.HeartBeatHandler;
import com.crossoverjie.cim.common.pojo.CIMUserInfo;
-import com.crossoverjie.cim.common.protocol.CIMRequestProto;
+import com.crossoverjie.cim.common.protocol.BaseCommand;
+import com.crossoverjie.cim.common.protocol.Request;
import com.crossoverjie.cim.common.util.NettyAttrUtil;
import com.crossoverjie.cim.server.kit.RouteHandler;
import com.crossoverjie.cim.server.kit.ServerHeartBeatHandlerImpl;
@@ -28,7 +28,7 @@
*/
@ChannelHandler.Sharable
@Slf4j
-public class CIMServerHandle extends SimpleChannelInboundHandler {
+public class CIMServerHandle extends SimpleChannelInboundHandler {
@@ -59,7 +59,7 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc
IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
if (idleStateEvent.state() == IdleState.READER_IDLE) {
- log.info("定时检测客户端端是否存活");
+ log.info("!!READER_IDLE!!");
HeartBeatHandler heartBeatHandler = SpringBeanFactory.getBean(ServerHeartBeatHandlerImpl.class) ;
heartBeatHandler.process(ctx) ;
@@ -71,10 +71,10 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc
@Override
- protected void channelRead0(ChannelHandlerContext ctx, CIMRequestProto.CIMReqProtocol msg) throws Exception {
+ protected void channelRead0(ChannelHandlerContext ctx, Request msg) throws Exception {
log.info("received msg=[{}]", msg.toString());
- if (msg.getType() == Constants.CommandType.LOGIN) {
+ if (msg.getCmd() == BaseCommand.LOGIN_REQUEST) {
//保存客户端与 Channel 之间的关系
SessionSocketHolder.put(msg.getRequestId(), (NioSocketChannel) ctx.channel());
SessionSocketHolder.saveSession(msg.getRequestId(), msg.getReqMsg());
@@ -82,11 +82,10 @@ protected void channelRead0(ChannelHandlerContext ctx, CIMRequestProto.CIMReqPro
}
//心跳更新时间
- if (msg.getType() == Constants.CommandType.PING){
+ if (msg.getCmd() == BaseCommand.PING){
NettyAttrUtil.updateReaderTime(ctx.channel(),System.currentTimeMillis());
//向客户端响应 pong 消息
- CIMRequestProto.CIMReqProtocol heartBeat = SpringBeanFactory.getBean("heartBeat",
- CIMRequestProto.CIMReqProtocol.class);
+ Request heartBeat = SpringBeanFactory.getBean("heartBeat", Request.class);
ctx.writeAndFlush(heartBeat).addListeners((ChannelFutureListener) future -> {
if (!future.isSuccess()) {
log.error("IO error,close Channel");
diff --git a/cim-server/src/main/java/com/crossoverjie/cim/server/init/CIMServerInitializer.java b/cim-server/src/main/java/com/crossoverjie/cim/server/init/CIMServerInitializer.java
index 0ca8d7f1..1d2aacfa 100644
--- a/cim-server/src/main/java/com/crossoverjie/cim/server/init/CIMServerInitializer.java
+++ b/cim-server/src/main/java/com/crossoverjie/cim/server/init/CIMServerInitializer.java
@@ -1,6 +1,6 @@
package com.crossoverjie.cim.server.init;
-import com.crossoverjie.cim.common.protocol.CIMRequestProto;
+import com.crossoverjie.cim.common.protocol.Request;
import com.crossoverjie.cim.server.handle.CIMServerHandle;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
@@ -29,7 +29,7 @@ protected void initChannel(Channel ch) throws Exception {
.addLast(new IdleStateHandler(11, 0, 0))
// google Protobuf 编解码
.addLast(new ProtobufVarint32FrameDecoder())
- .addLast(new ProtobufDecoder(CIMRequestProto.CIMReqProtocol.getDefaultInstance()))
+ .addLast(new ProtobufDecoder(Request.getDefaultInstance()))
.addLast(new ProtobufVarint32LengthFieldPrepender())
.addLast(new ProtobufEncoder())
.addLast(cimServerHandle);
diff --git a/cim-server/src/main/java/com/crossoverjie/cim/server/kit/RegistryMetaStore.java b/cim-server/src/main/java/com/crossoverjie/cim/server/kit/RegistryMetaStore.java
new file mode 100644
index 00000000..60b8825b
--- /dev/null
+++ b/cim-server/src/main/java/com/crossoverjie/cim/server/kit/RegistryMetaStore.java
@@ -0,0 +1,55 @@
+package com.crossoverjie.cim.server.kit;
+
+import com.crossoverjie.cim.common.metastore.MetaStore;
+import com.crossoverjie.cim.common.metastore.ZkConfiguration;
+import com.crossoverjie.cim.server.config.AppConfiguration;
+import com.crossoverjie.cim.server.util.SpringBeanFactory;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+
+
+/**
+ * Function:
+ *
+ * @author crossoverJie
+ * Date: 2018/8/24 01:37
+ * @since JDK 1.8
+ */
+@Slf4j
+public class RegistryMetaStore implements Runnable {
+
+
+ private MetaStore metaStore;
+
+ private AppConfiguration appConfiguration ;
+
+ private String ip;
+ private int cimServerPort;
+ private int httpPort;
+ public RegistryMetaStore(MetaStore metaStore, String ip, int cimServerPort, int httpPort) {
+ this.ip = ip;
+ this.cimServerPort = cimServerPort;
+ this.httpPort = httpPort ;
+ this.metaStore = metaStore;
+ appConfiguration = SpringBeanFactory.getBean(AppConfiguration.class) ;
+ }
+
+ @SneakyThrows
+ @Override
+ public void run() {
+
+ if (!appConfiguration.isZkSwitch()){
+ log.info("Skip registry to metaStore");
+ return;
+ }
+
+ ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3);
+ metaStore.initialize(ZkConfiguration.builder()
+ .metaServiceUri(appConfiguration.getZkAddr())
+ .timeoutMs(appConfiguration.getZkConnectTimeout())
+ .retryPolicy(retryPolicy)
+ .build());
+ metaStore.addServer(ip, cimServerPort, httpPort);
+ }
+}
\ No newline at end of file
diff --git a/cim-server/src/main/java/com/crossoverjie/cim/server/kit/RegistryZK.java b/cim-server/src/main/java/com/crossoverjie/cim/server/kit/RegistryZK.java
deleted file mode 100644
index e68d0617..00000000
--- a/cim-server/src/main/java/com/crossoverjie/cim/server/kit/RegistryZK.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.crossoverjie.cim.server.kit;
-
-import com.crossoverjie.cim.server.config.AppConfiguration;
-import com.crossoverjie.cim.server.util.SpringBeanFactory;
-import lombok.extern.slf4j.Slf4j;
-
-
-/**
- * Function:
- *
- * @author crossoverJie
- * Date: 2018/8/24 01:37
- * @since JDK 1.8
- */
-@Slf4j
-public class RegistryZK implements Runnable {
-
-
- private ZKit zKit;
-
- private AppConfiguration appConfiguration ;
-
- private String ip;
- private int cimServerPort;
- private int httpPort;
-
- public RegistryZK(String ip, int cimServerPort,int httpPort) {
- this.ip = ip;
- this.cimServerPort = cimServerPort;
- this.httpPort = httpPort ;
- zKit = SpringBeanFactory.getBean(ZKit.class) ;
- appConfiguration = SpringBeanFactory.getBean(AppConfiguration.class) ;
- }
-
- @Override
- public void run() {
-
- //创建父节点
- zKit.createRootNode();
-
- //是否要将自己注册到 ZK
- if (appConfiguration.isZkSwitch()){
- String path = appConfiguration.getZkRoot() + "/ip-" + ip + ":" + cimServerPort + ":" + httpPort;
- zKit.createNode(path);
- log.info("Registry zookeeper success, msg=[{}]", path);
- }
-
-
- }
-}
\ No newline at end of file
diff --git a/cim-server/src/main/java/com/crossoverjie/cim/server/kit/RouteHandler.java b/cim-server/src/main/java/com/crossoverjie/cim/server/kit/RouteHandler.java
index a70aadb9..58ac16c6 100644
--- a/cim-server/src/main/java/com/crossoverjie/cim/server/kit/RouteHandler.java
+++ b/cim-server/src/main/java/com/crossoverjie/cim/server/kit/RouteHandler.java
@@ -1,12 +1,13 @@
package com.crossoverjie.cim.server.kit;
-import com.crossoverjie.cim.common.core.proxy.ProxyManager;
+import com.crossoverjie.cim.common.core.proxy.RpcProxyManager;
import com.crossoverjie.cim.common.pojo.CIMUserInfo;
import com.crossoverjie.cim.route.api.RouteApi;
import com.crossoverjie.cim.route.api.vo.req.ChatReqVO;
import com.crossoverjie.cim.server.config.AppConfiguration;
import com.crossoverjie.cim.server.util.SessionSocketHolder;
import io.netty.channel.socket.nio.NioSocketChannel;
+import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Response;
@@ -26,20 +27,22 @@
@Slf4j
public class RouteHandler {
- @Autowired
+ @Resource
private OkHttpClient okHttpClient;
- @Autowired
+ @Resource
private AppConfiguration configuration;
+ @Resource
+ private RouteApi routeApi;
+
/**
* 用户下线
*
* @param userInfo
* @param channel
- * @throws IOException
*/
- public void userOffLine(CIMUserInfo userInfo, NioSocketChannel channel) throws IOException {
+ public void userOffLine(CIMUserInfo userInfo, NioSocketChannel channel) {
if (userInfo != null) {
log.info("Account [{}] offline", userInfo.getUserName());
SessionSocketHolder.removeSession(userInfo.getUserId());
@@ -58,16 +61,8 @@ public void userOffLine(CIMUserInfo userInfo, NioSocketChannel channel) throws I
* @throws IOException
*/
public void clearRouteInfo(CIMUserInfo userInfo) {
- RouteApi routeApi = new ProxyManager<>(RouteApi.class, configuration.getRouteUrl(), okHttpClient).getInstance();
- Response response = null;
ChatReqVO vo = new ChatReqVO(userInfo.getUserId(), userInfo.getUserName());
- try {
- response = (Response) routeApi.offLine(vo);
- } catch (Exception e){
- log.error("Exception",e);
- }finally {
- response.body().close();
- }
+ routeApi.offLine(vo);
}
}
diff --git a/cim-server/src/main/java/com/crossoverjie/cim/server/kit/ZKit.java b/cim-server/src/main/java/com/crossoverjie/cim/server/kit/ZKit.java
deleted file mode 100644
index 6a9839c9..00000000
--- a/cim-server/src/main/java/com/crossoverjie/cim/server/kit/ZKit.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.crossoverjie.cim.server.kit;
-
-import com.crossoverjie.cim.server.config.AppConfiguration;
-import lombok.extern.slf4j.Slf4j;
-import org.I0Itec.zkclient.ZkClient;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-/**
- * Function: Zookeeper 工具
- *
- * @author crossoverJie
- * Date: 2018/8/19 00:33
- * @since JDK 1.8
- */
-@Component
-@Slf4j
-public class ZKit {
-
- @Autowired
- private ZkClient zkClient;
-
- @Autowired
- private AppConfiguration appConfiguration ;
-
- /**
- * 创建父级节点
- */
- public void createRootNode(){
- boolean exists = zkClient.exists(appConfiguration.getZkRoot());
- if (exists){
- return;
- }
-
- //创建 root
- zkClient.createPersistent(appConfiguration.getZkRoot()) ;
- }
-
- /**
- * 写入指定节点 临时目录
- *
- * @param path
- */
- public void createNode(String path) {
- zkClient.createEphemeral(path);
- }
-
-}
diff --git a/cim-server/src/main/java/com/crossoverjie/cim/server/server/CIMServer.java b/cim-server/src/main/java/com/crossoverjie/cim/server/server/CIMServer.java
index f823dac7..89a3e73a 100644
--- a/cim-server/src/main/java/com/crossoverjie/cim/server/server/CIMServer.java
+++ b/cim-server/src/main/java/com/crossoverjie/cim/server/server/CIMServer.java
@@ -1,7 +1,7 @@
package com.crossoverjie.cim.server.server;
-import com.crossoverjie.cim.common.constant.Constants;
-import com.crossoverjie.cim.common.protocol.CIMRequestProto;
+import com.crossoverjie.cim.common.protocol.BaseCommand;
+import com.crossoverjie.cim.common.protocol.Request;
import com.crossoverjie.cim.server.api.vo.req.SendMsgReqVO;
import com.crossoverjie.cim.server.init.CIMServerInitializer;
import com.crossoverjie.cim.server.util.SessionSocketHolder;
@@ -86,10 +86,11 @@ public void sendMsg(SendMsgReqVO sendMsgReqVO){
log.error("client {} offline!", sendMsgReqVO.getUserId());
return;
}
- CIMRequestProto.CIMReqProtocol protocol = CIMRequestProto.CIMReqProtocol.newBuilder()
+ Request protocol = Request.newBuilder()
.setRequestId(sendMsgReqVO.getUserId())
.setReqMsg(sendMsgReqVO.getMsg())
- .setType(Constants.CommandType.MSG)
+ .putAllProperties(sendMsgReqVO.getProperties())
+ .setCmd(BaseCommand.MESSAGE)
.build();
ChannelFuture future = socketChannel.writeAndFlush(protocol);
diff --git a/cim-server/src/main/resources/banner.txt b/cim-server/src/main/resources/banner.txt
index 97b15b91..1fc2e873 100644
--- a/cim-server/src/main/resources/banner.txt
+++ b/cim-server/src/main/resources/banner.txt
@@ -1,14 +1,8 @@
- ▄████▄ ██▓ ███▄ ▄███▓
-▒██▀ ▀█ ▓██▒▓██▒▀█▀ ██▒
-▒▓█ ▄ ▒██▒▓██ ▓██░
-▒▓▓▄ ▄██▒░██░▒██ ▒██
-▒ ▓███▀ ░░██░▒██▒ ░██▒
-░ ░▒ ▒ ░░▓ ░ ▒░ ░ ░
- ░ ▒ ▒ ░░ ░ ░
-░ ▒ ░░ ░
-░ ░ ░ ░
-░
+ _
+ ____(_)_ _ ___ ___ _____ _____ ____
+/ __/ / ' \ (_- -_) __/ |/ / -_) __/
+\__/_/_/_/_/ /___/\__/_/ |___/\__/_/
Power by @crossoverJie
diff --git a/cim-server/src/test/com/crossoverjie/cim/server/util/NettyAttrUtilTest.java b/cim-server/src/test/com/crossoverjie/cim/server/util/NettyAttrUtilTest.java
index 4401dae4..d2c9318f 100644
--- a/cim-server/src/test/com/crossoverjie/cim/server/util/NettyAttrUtilTest.java
+++ b/cim-server/src/test/com/crossoverjie/cim/server/util/NettyAttrUtilTest.java
@@ -1,9 +1,9 @@
package com.crossoverjie.cim.server.util;
-import org.junit.Test;
import java.util.concurrent.TimeUnit;
+import org.junit.jupiter.api.Test;
public class NettyAttrUtilTest {
diff --git a/pic/architecture.png b/pic/architecture.png
new file mode 100644
index 00000000..0444d70f
Binary files /dev/null and b/pic/architecture.png differ
diff --git a/pic/delay.gif b/pic/delay.gif
new file mode 100644
index 00000000..0353dd54
Binary files /dev/null and b/pic/delay.gif differ
diff --git a/pic/demo.gif b/pic/demo.gif
new file mode 100644
index 00000000..c0bd7cf0
Binary files /dev/null and b/pic/demo.gif differ
diff --git a/pic/flow.png b/pic/flow.png
new file mode 100644
index 00000000..7dcba603
Binary files /dev/null and b/pic/flow.png differ
diff --git a/pom.xml b/pom.xml
index 297860de..73aeef08 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,136 +1,259 @@
- 4.0.0
- com.crossoverjie.netty
- cim
- 1.0.0-SNAPSHOT
- pom
-
- cim
- Spring Boot
-
-
-
- 4.12
- 4.1.68.Final
- UTF-8
- UTF-8
- 2.5.0
-
-
-
- org.springframework.boot
- spring-boot-starter-parent
- 3.3.0
-
-
-
-
- cim-server
- cim-client
- cim-common
- cim-forward-route
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
+ com.crossoverjie.netty
+ cim
+ 1.0.0-SNAPSHOT
+ pom
+
+ cim
+ Spring Boot
+
+
+
+ 4.12
+ 4.1.68.Final
+ UTF-8
+ UTF-8
+ 2.5.0
+ 5.1.0
+ 3.8.4
+ 0.8.11
+ 4.28.3
+ 1.19.0
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.3.0
+
+
+
+
+ cim-server
+ cim-client
+ cim-common
+ cim-forward-route
cim-rout-api
cim-server-api
+ cim-integration-test
+ cim-client-sdk
-
-
-
-
- com.github.xiaoymin
- knife4j-openapi3-jakarta-spring-boot-starter
- 4.4.0
-
-
-
- com.squareup.okhttp3
- okhttp
- 3.3.1
-
-
- com.github.sgroschupf
- zkclient
- 0.1
-
-
-
- com.crossoverjie.netty
- cim-common
- 1.0.1-SNAPSHOT
-
-
-
- com.crossoverjie.netty
- cim-rout-api
- 1.0.1-SNAPSHOT
-
-
-
- com.crossoverjie.netty
- cim-server-api
- 1.0.1-SNAPSHOT
-
-
-
- com.google.protobuf
- protobuf-java
- 3.16.3
-
-
-
-
-
- io.netty
- netty-all
- ${netty.version}
-
-
-
- junit
- junit
- ${junit.version}
-
-
-
- com.alibaba
- fastjson
- 1.2.83
-
-
-
- com.google.guava
- guava
- 19.0
-
-
-
- de.codecentric
- spring-boot-admin-starter-client
- 1.5.7
-
-
-
- jakarta.validation
- jakarta.validation-api
- 3.0.0
-
-
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
-
- 17
- 17
-
-
-
-
+
+
+
+
+ com.github.xiaoymin
+ knife4j-openapi3-jakarta-spring-boot-starter
+ 4.4.0
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 3.3.1
+
+
+
+ com.101tec
+ zkclient
+ 0.11
+
+
+
+
+ org.apache.curator
+ curator-recipes
+ ${curator.version}
+
+
+
+ org.apache.curator
+ curator-x-discovery
+ ${curator.version}
+
+
+
+
+ org.apache.zookeeper
+ zookeeper
+ ${zookeeper.version}
+
+
+ net.java.dev.javacc
+ javacc
+
+
+ ch.qos.logback
+ *
+
+
+ io.netty
+ *
+
+
+
+
+ org.apache.zookeeper
+ zookeeper
+ ${zookeeper.version}
+ test-jar
+
+
+ org.slf4j
+ slf4j-api
+
+
+ ch.qos.logback
+ *
+
+
+ io.netty
+ *
+
+
+
+
+
+ com.crossoverjie.netty
+ cim-common
+ ${project.version}
+
+
+ com.crossoverjie.netty
+ cim-client-sdk
+ ${project.version}
+
+
+
+ com.crossoverjie.netty
+ cim-rout-api
+ ${project.version}
+
+
+
+ com.crossoverjie.netty
+ cim-server-api
+ ${project.version}
+
+
+
+ com.google.protobuf
+ protobuf-java
+ ${protobuf-java.version}
+
+
+
+
+ io.netty
+ netty-all
+ ${netty.version}
+
+
+
+ junit
+ junit
+ ${junit.version}
+
+
+
+ com.alibaba
+ fastjson
+ 1.2.83
+
+
+
+ com.google.guava
+ guava
+ 19.0
+
+
+
+ de.codecentric
+ spring-boot-admin-starter-client
+ 1.5.7
+
+
+
+ jakarta.validation
+ jakarta.validation-api
+ 3.0.0
+
+
+
+ com.clever-cloud
+ testcontainers-zookeeper
+ 0.1.3
+ test
+
+
+
+ com.redis
+ testcontainers-redis
+ 2.2.2
+ test
+
+
+
+
+
+
+
+
+ x86
+
+ true
+
+
+
+
+
+
+ aarch
+
+
+ aarch64
+
+
+
+ osx-x86_64
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 17
+ 17
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ ${jacoco-maven-plugin.version}
+
+
+
+ prepare-agent
+
+
+
+ report
+ test
+
+ report
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/BaseRequestProto.proto b/protocol/BaseRequestProto.proto
deleted file mode 100644
index dde24203..00000000
--- a/protocol/BaseRequestProto.proto
+++ /dev/null
@@ -1,14 +0,0 @@
-syntax = "proto2";
-
-package protocol;
-
-option java_package = "com.crossoverjie.cim.common.protocol";
-option java_outer_classname = "CIMRequestProto";
-
-message CIMReqProtocol {
- required int64 requestId = 2;
- required string reqMsg = 1;
- required int32 type = 3;
-
-}
-
diff --git a/protocol/BaseResponseProto.proto b/protocol/BaseResponseProto.proto
deleted file mode 100644
index b9bc6d16..00000000
--- a/protocol/BaseResponseProto.proto
+++ /dev/null
@@ -1,13 +0,0 @@
-syntax = "proto2";
-
-package protocol;
-
-option java_package = "com.crossoverjie.cim.common.protocol";
-option java_outer_classname = "CIMResponseProto";
-
-message CIMResProtocol {
- required int64 responseId = 2;
- required string resMsg = 1;
- required int32 type = 3;
-
-}
diff --git a/script/build.sh b/script/build.sh
new file mode 100644
index 00000000..d463deb5
--- /dev/null
+++ b/script/build.sh
@@ -0,0 +1 @@
+# todo build
\ No newline at end of file