Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client SDK #148

Merged
merged 18 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions cim-client-sdk/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.crossoverjie.netty</groupId>
<artifactId>cim</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>

<artifactId>cim-client-sdk</artifactId>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>


<dependencies>
<dependency>
<groupId>com.crossoverjie.netty</groupId>
<artifactId>cim-common</artifactId>
</dependency>

<dependency>
<groupId>com.crossoverjie.netty</groupId>
<artifactId>cim-rout-api</artifactId>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.crossoverjie.netty</groupId>
<artifactId>cim-integration-test</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -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<Void> sendP2PAsync(P2PReqVO p2PReqVO);

default void sendGroup(String msg) throws Exception{
sendGroupAsync(msg).get();
};

CompletableFuture<Void> sendGroupAsync(String msg);

ClientState.State getState();

ClientConfigurationData.Auth getAuth();

Set<CIMUserInfo> getOnlineUser() throws Exception;

Optional<CIMServerResVO> getServerInfo();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
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 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);
}
Original file line number Diff line number Diff line change
@@ -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> 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();
}
}
Original file line number Diff line number Diff line change
@@ -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) {

}
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -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> 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);

Check warning on line 41 in cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/RouteManager.java

View check run for this annotation

Codecov / codecov/patch

cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/RouteManager.java#L40-L41

Added lines #L40 - L41 were not covered by tests
}
}
return cimServerResVO.getDataBody();
}

public CompletableFuture<Void> sendP2P(CompletableFuture<Void> future, P2PReqVO p2PReqVO) {
return CompletableFuture.runAsync(() -> {
try {
BaseResponse<NULLBody> response = routeApi.p2pRoute(p2PReqVO);
if (response.getCode().equals(StatusEnum.OFF_LINE.getCode())) {
future.completeExceptionally(new CIMException(StatusEnum.OFF_LINE));

Check warning on line 52 in cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/RouteManager.java

View check run for this annotation

Codecov / codecov/patch

cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/RouteManager.java#L52

Added line #L52 was not covered by tests
}
future.complete(null);
} catch (Exception e) {
future.completeExceptionally(e);
event.error("send p2p msg error", e);

Check warning on line 57 in cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/RouteManager.java

View check run for this annotation

Codecov / codecov/patch

cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/RouteManager.java#L55-L57

Added lines #L55 - L57 were not covered by tests
}
});
}

public CompletableFuture<Void> sendGroupMsg(ChatReqVO chatReqVO) {
return CompletableFuture.runAsync(() -> {
try {
routeApi.groupRoute(chatReqVO);
} catch (Exception e) {
event.error("send group msg error", e);

Check warning on line 67 in cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/RouteManager.java

View check run for this annotation

Codecov / codecov/patch

cim-client-sdk/src/main/java/com/crossoverjie/cim/client/sdk/RouteManager.java#L66-L67

Added lines #L66 - L67 were not covered by tests
}
});
}

public void offLine(Long userId) {
ChatReqVO vo = new ChatReqVO(userId, "offLine");
routeApi.offLine(vo);
}

public Set<CIMUserInfo> onlineUser() throws Exception {
BaseResponse<Set<CIMUserInfo>> onlineUsersResVO = routeApi.onlineUser();
return onlineUsersResVO.getDataBody();
}
}
Loading