add socket third core service and update version

:wq
git #
This commit is contained in:
zhongchao
2021-10-12 18:04:24 +08:00
parent 93182e0d2e
commit 0397c95ee0
39 changed files with 2559 additions and 30 deletions

View File

@@ -1,7 +1,7 @@
package com.mogo.cloud.live.socket;
import com.mogo.cloud.TelephoneUtil;
import com.zhidao.ptech.shadow.server.protocol.DeviceInfo;
import com.zhidao.utils.common.TelephoneUtil;
public class SocketRequestUtils {
public static byte[] buildDeviceData(int c1, int c2) {

View File

@@ -26,21 +26,26 @@ android {
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
// socket-for-sdk 长链 http://wiki.zhidaohulian.com/pages/viewpage.action?pageId=48956182 外部SDK版本
api 'com.zhidao.socket:built-in-socket:1.0.23-SNAPSHOT'
// 上报位置 http://wiki.zhidaohulian.com/pages/viewpage.action?pageId=48956200
implementation 'com.zhidao.locupload:loc-upload-sdk:1.2.0'
implementation 'com.google.protobuf:protobuf-java:3.12.4'
implementation 'io.netty:netty-all:4.1.8.Final'
api 'com.zhidao.ptech:connsvr-protoco:0.1.37'
api 'com.elegant.network:network:1.1.28'
api 'com.elegant.analytics:analytics:1.1.28'
// socket-for-internal 长链 内部SDK版本
implementation 'com.zhidao.socketsdk:socketsdk:2.1.4'
implementation 'com.google.protobuf:protobuf-java:3.12.4'
// 上报位置 http://wiki.zhidaohulian.com/pages/viewpage.action?pageId=48956200
implementation 'com.zhidao.locupload:loc-upload-sdk:1.2.0'
if (Boolean.valueOf(RELEASE)) {
implementation "com.mogo.cloud:passport:${MOGO_PASSPORT_VERSION}"
implementation "com.mogo.cloud:utils:${MOGO_UTILS_VERSION}"
} else {
implementation project(path: ':foudations:mogo-passport')
implementation project(path: ':foudations:mogo-utils')
}
}
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()

View File

@@ -3,7 +3,7 @@ package com.mogo.cloud.socket;
import android.content.Context;
import com.mogo.cloud.socket.entity.MsgBody;
import com.zhidao.socket.ConnectionLifecycleListener;
import com.mogo.cloud.socket.third.core.ConnectionLifecycleListener;
/**

View File

@@ -12,9 +12,9 @@ import com.mogo.cloud.socket.entity.MsgBody;
import com.mogo.cloud.socket.entity.SocketDownData;
import com.mogo.cloud.socket.internal.InternalSocketManager;
import com.mogo.cloud.socket.third.ThirdSocketManager;
import com.mogo.cloud.socket.third.core.ConnectionLifecycleListener;
import com.mogo.cloud.utils.logger.Logger;
import com.zhidao.ptech.connsvr.protocol.MogoConnsvr;
import com.zhidao.socket.ConnectionLifecycleListener;
import java.util.ArrayList;
import java.util.Iterator;

View File

@@ -4,12 +4,10 @@ package com.mogo.cloud.socket;
import com.mogo.cloud.passport.MoGoAiCloudClient;
import com.mogo.cloud.passport.MoGoAiCloudClientConfig;
import com.zhidao.socket.Environment;
import com.mogo.cloud.socket.third.core.Environment;
import static com.mogo.cloud.httpdns.MogoHttpDnsConfig.HTTP_DNS_ENV_DEMO;
import static com.mogo.cloud.httpdns.MogoHttpDnsConfig.HTTP_DNS_ENV_DEV;
import static com.mogo.cloud.httpdns.MogoHttpDnsConfig.HTTP_DNS_ENV_QA;
import static com.mogo.cloud.httpdns.MogoHttpDnsConfig.HTTP_DNS_ENV_RELEASE;
import androidx.annotation.Keep;
@@ -27,11 +25,11 @@ public class SocketServicesConstants {
MoGoAiCloudClientConfig cloudClientConfig = MoGoAiCloudClient.getInstance().getAiCloudClientConfig();
switch (cloudClientConfig.getNetMode()) {
case HTTP_DNS_ENV_DEV:
return com.zhidao.socket.Environment.dev;
return Environment.dev;
case HTTP_DNS_ENV_QA:
return com.zhidao.socket.Environment.qa;
return Environment.qa;
default:
return com.zhidao.socket.Environment.release;
return Environment.release;
}
}
}

View File

@@ -6,14 +6,14 @@ import com.mogo.cloud.passport.MoGoAiCloudClient;
import com.mogo.cloud.passport.MoGoAiCloudClientConfig;
import com.mogo.cloud.socket.SocketManager;
import com.mogo.cloud.socket.SocketServicesConstants;
import com.mogo.cloud.socket.third.core.Callback;
import com.mogo.cloud.socket.third.core.CallbackManager;
import com.mogo.cloud.socket.third.core.ConnectionLifecycleListener;
import com.mogo.cloud.socket.third.core.SocketClient;
import com.mogo.cloud.socket.third.core.SocketConfig;
import com.mogo.cloud.utils.logger.Logger;
import com.zhidao.locupload.Platform;
import com.zhidao.ptech.connsvr.commom.protocol.MogoCommon;
import com.zhidao.socket.Callback;
import com.zhidao.socket.CallbackManager;
import com.zhidao.socket.ConnectionLifecycleListener;
import com.zhidao.socket.SocketClient;
import com.zhidao.socket.SocketConfig;
import static com.mogo.cloud.socket.SocketServicesConstants.SOCKET_CHANNEL_ID;
import static com.mogo.cloud.socket.SocketServicesConstants.TAG;

View File

@@ -0,0 +1,30 @@
package com.mogo.cloud.socket.third.analytics;
import com.elegant.analytics.Analytics;
import org.json.JSONObject;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class EventManager {
private static SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA);
public static void trackEvent(String event, JSONObject jsonObject) {
if (jsonObject == null) {
return;
}
try {
jsonObject.put("time", getCurrentTime());
Analytics.getInstance().track(event, jsonObject);
} catch (Exception e) {
e.printStackTrace();
}
}
private static String getCurrentTime() {
return format.format(new Date());
}
}

View File

@@ -0,0 +1,74 @@
package com.mogo.cloud.socket.third.analytics;
import android.text.TextUtils;
import com.elegant.log.simplelog.Logger;
import com.elegant.utils.CheckUtils;
import com.mogo.cloud.socket.third.core.SocketConfig;
import org.json.JSONException;
import org.json.JSONObject;
public class EventRequest {
//socket授权状态
private static final String SOCKET_STATUS = "socket_status";
//异常情况
private static final String EXCEPTION = "exception";
private static final String TAG = "EventRequest";
/**
* socket状态相关
*
* @param status socket 状态
*/
public static void trackSocketStatus(String status, String desc) {
if(!SocketConfig.instance().isAnalyticsOpen()){
Logger.d(TAG,"analytics is closed");
return;
}
EventManager.trackEvent(SOCKET_STATUS, buildAuthStatus(status, desc));
}
/**
* 埋点异常情况
*
* @param reason 异常场景
*/
public static void trackException(String reason) {
if(!SocketConfig.instance().isAnalyticsOpen()){
Logger.d(TAG,"analytics is closed");
return;
}
if (TextUtils.isEmpty(reason)) {
return;
}
EventManager.trackEvent(EXCEPTION, buildException(reason));
}
private static JSONObject buildAuthStatus(String status, String desc) {
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("socket_status", status);
jsonObject.put("desc", desc);
if(SocketConfig.instance().getAppContext() != null){
jsonObject.put("net", CheckUtils.isNetworkConnected(SocketConfig.instance().getAppContext()));
}
return jsonObject;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
private static JSONObject buildException(String reason) {
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("exception", reason);
return jsonObject;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}

View File

@@ -0,0 +1,17 @@
package com.mogo.cloud.socket.third.analytics;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.SOURCE)
public @interface SocketStatus {
//socket 断开连接
String socket_disconnect = "socket_disconnect";
//鉴权失败
String auth_rsp_failed = "auth_rsp_failed";
//发送用户信息反馈失败
String send_userInfo_rsp_failed = "send_userInfo_rsp_failed";
}

View File

@@ -0,0 +1,16 @@
package com.mogo.cloud.socket.third.core;
import android.support.annotation.NonNull;
public interface Callback {
/**
* Callback's method invoked when message is received by client
*
* @param manager callback manager.
* @param message message.
*/
void update(@NonNull CallbackManager manager, @NonNull byte[] message, String appId, long msgId);
void onAck(@NonNull CallbackManager manager, @NonNull byte[] header, byte[] content);
}

View File

@@ -0,0 +1,51 @@
package com.mogo.cloud.socket.third.core;
import android.support.annotation.NonNull;
import android.support.v4.util.ArraySet;
import com.mogo.cloud.utils.logger.Logger;
import java.util.Set;
public final class CallbackManager {
private final Set<Callback> observers = new ArraySet<>();
private CallbackManager() {
}
public static CallbackManager getInstance() {
return SingletonHolder.INSTANCE;
}
private static final class SingletonHolder {
private final static CallbackManager INSTANCE = new CallbackManager();
}
public synchronized void register(Callback callback) {
if (callback == null) {
Logger.i(SocketConstants.TAG, "Can not register a callback that is null.");
return;
}
observers.add(callback);
}
public synchronized void unregister(Callback callback) {
observers.remove(callback);
}
public synchronized void unregisterAll() {
observers.clear();
}
public synchronized void notify(@NonNull byte[] content, String appId, long msgId) {
for (Callback callback : observers) {
callback.update(this, content, appId, msgId);
}
}
public synchronized void ack(@NonNull byte[] header, byte[] content) {
for (Callback callback : observers) {
callback.onAck(this, header, content);
}
}
}

View File

@@ -0,0 +1,57 @@
package com.mogo.cloud.socket.third.core;
import android.support.v4.util.ArraySet;
import com.mogo.cloud.utils.logger.Logger;
import java.util.Set;
public class ConnCallbackManager {
private ConnCallbackManager() {
}
public static ConnCallbackManager getInstance() {
return SingletonHolder.INSTANCE;
}
private static final class SingletonHolder {
private final static ConnCallbackManager INSTANCE = new ConnCallbackManager();
}
private final Set<ConnectionLifecycleListener> observers = new ArraySet<>();
public synchronized void register(ConnectionLifecycleListener callback) {
if (callback == null) {
Logger.i(SocketConstants.TAG, "Can not register a callback that is null.");
return;
}
observers.add(callback);
}
public synchronized void unregister(ConnectionLifecycleListener callback) {
observers.remove(callback);
}
public synchronized void unregisterAll() {
observers.clear();
}
public void onConnectFailure() {
for (ConnectionLifecycleListener callback : observers) {
callback.onConnectFailure();
}
}
public void onConnectSuccess() {
for (ConnectionLifecycleListener callback : observers) {
callback.onConnectSuccess();
}
}
public void onConnectLost(boolean reconnect) {
for (ConnectionLifecycleListener callback : observers) {
callback.onConnectLost(reconnect);
}
}
}

View File

@@ -0,0 +1,13 @@
package com.mogo.cloud.socket.third.core;
public abstract class ConnectionLifecycleListener {
public void onConnectFailure() {
}
public void onConnectSuccess() {
}
public void onConnectLost(boolean reconnect) {
}
}

View File

@@ -0,0 +1,27 @@
package com.mogo.cloud.socket.third.core;
public enum Environment {
release(3),
qa(2),
dev(1),
;
private int env;
Environment(int env) {
this.env = env;
}
public int getEnv(){
return env;
}
public static Environment get(int env){
for(Environment environment : values()){
if(environment.getEnv() == env){
return environment;
}
}
return release;
}
}

View File

@@ -0,0 +1,215 @@
package com.mogo.cloud.socket.third.core;
import android.content.Context;
import android.text.TextUtils;
import com.elegant.network.NetConfig;
import com.elegant.utils.UiThreadHandler;
import com.mogo.cloud.socket.third.core.client.ClientSocketManager;
import com.mogo.cloud.socket.third.core.network.RequestManager;
import com.mogo.cloud.socket.third.core.network.model.SocketAddressData;
import com.mogo.cloud.socket.third.utils.RequestUtil;
import com.mogo.cloud.utils.logger.Logger;
import com.zhidao.ptech.connsvr.commom.protocol.MogoCommon;
import com.zhidao.ptech.connsvr.payload.protocol.MogoPayload;
import com.zhidao.ptech.connsvr.protocol.MogoConnsvr;
public class SocketClient {
private static final String TAG = "SocketClient";
private Context mAppContext;
private volatile boolean mHasStarted;
private SocketClient() {
}
public static SocketClient getInstance() {
return SingletonHolder.INSTANCE;
}
private static final class SingletonHolder {
private static final SocketClient INSTANCE = new SocketClient();
}
/**
* 启动socket
*
* @param context app context
*/
public synchronized void start(Context context) {
if (mHasStarted) {
Logger.d(TAG, "socket already started");
return;
}
if (context == null) {
throw new NullPointerException("context cannot be null");
}
Logger.d(TAG, "start socket");
//ensure context be set
SocketConfig.instance().setAppContext(mAppContext = context.getApplicationContext());
initNetConfig();
requestSocketAddress();
mHasStarted = true;
}
/**
* 停止socket
*/
public synchronized void stop() {
if (!mHasStarted) {
Logger.d(TAG, "socket already stopped");
return;
}
ClientSocketManager.getInstance().close();
mHasStarted = false;
Logger.d(TAG, "stop");
}
/**
* 注册Socket Callback
*
* @param callback 用于接收socket消息的callback
*/
public void registerSocketCallback(Callback callback) {
CallbackManager.getInstance().register(callback);
}
/**
* 注销Socket Callback
*
* @param callback 用于接收socket消息的callback
*/
public void unregisterSocketCallback(Callback callback) {
CallbackManager.getInstance().unregister(callback);
}
/**
* 通过socket发送上行数据
*
* @param appId 此app id可被业务定制不用于建立长连接
* @param productLine 产品线,参考{@link MogoCommon.Product}
* @param payload 上行数据,使用{@link MogoConnsvr.Payload}构建数据
* @param msgType msg类型参考{@link MogoPayload.PayloadMsgType}
* @param ack 是否需要server回执如果为true会在{@link Callback#onAck(CallbackManager, byte[], byte[])}中收到
* @param msgId msg id可自定义比如时间戳
*/
public void sendData(String appId,
int productLine,
byte[] payload,
int msgType,
boolean ack,
long msgId) {
RequestUtil.sendPayloadData(appId, productLine, payload, msgType, ack, msgId);
}
/**
* 注册socket连接状态监听
*
* @param callback 用于接收socket连接状态callback
*/
public void registerSocketConnCallback(ConnectionLifecycleListener callback) {
if (callback != null) {
ConnCallbackManager.getInstance().register(callback);
}
}
/**
* 注销socket连接状态监听
*
* @param callback 用于接收socket连接状态callback
*/
public void unregisterSocketConnCallback(ConnectionLifecycleListener callback) {
if (callback != null) {
ConnCallbackManager.getInstance().unregister(callback);
}
}
private void initNetConfig() {
NetConfig.instance().
setLoggable(SocketConfig.instance().isDebug()).
setAppContext(mAppContext);
}
private void requestSocketAddress() {
RequestManager.requestSocketAddress(mAppContext, new RequestManager.SocketAddressCallback() {
@Override
public void onGetSocketAddressSuccess(SocketAddressData addressData) {
if (addressData.result != null && checkHost(addressData.result.ip) && checkPort(addressData.result.port)) {
internalStart(addressData.result.ip, addressData.result.port);
Logger.d(TAG, "network--->ip:" + addressData.result.ip + " & port: " + addressData.result.port);
} else {
retryGetAddress(1000L); //todo 时间调整为1秒后续在重连时增加网络状态验证以及增加链路日志
}
}
@Override
public void onGetSocketAddressFailed(int code, String msg) {
Logger.d(TAG, "onFailed-->" + code + ":" + msg);
retryGetAddress(1000L); //todo 时间调整为1秒后续在重连时增加网络状态验证以及增加链路日志
}
});
}
private final Runnable mRequestSocketAddressTask = () -> {
Logger.d(TAG, "get socket address");
requestSocketAddress();
};
private void internalStart(String host, int port) {
Logger.d(TAG, "internalStart-->host: " + host + " & port: " + port);
ClientSocketManager.getInstance().setConnectionLifecycleListener(connectionLifecycleListener);
ClientSocketManager.getInstance().start(host, port);
}
private final ConnectionLifecycleListener connectionLifecycleListener = new ConnectionLifecycleListener() {
@Override
public void onConnectLost(boolean reconnect) {
super.onConnectLost(reconnect);
Logger.d(TAG, "---onConnectLost");
ConnCallbackManager.getInstance().onConnectLost(reconnect);
if (reconnect) {
Logger.d(TAG, "---onConnectLost reconnect");
retryGetAddress(1000L);//1-7s //todo 时间调整为1秒后续在重连时增加网络状态验证以及增加链路日志
}
}
@Override
public void onConnectFailure() {
super.onConnectFailure();
Logger.d(TAG, "---onConnectFailure");
ConnCallbackManager.getInstance().onConnectFailure();
retryGetAddress(1000L);//3-6s //todo 时间调整为1秒后续在重连时增加网络状态验证以及增加链路日志
}
@Override
public void onConnectSuccess() {
super.onConnectSuccess();
Logger.d(TAG, "---onConnectSuccess");
ConnCallbackManager.getInstance().onConnectSuccess();
}
};
private void retryGetAddress(long delayedInMillis) {
UiThreadHandler.removeCallbacks(mRequestSocketAddressTask);
UiThreadHandler.postDelayed(mRequestSocketAddressTask, delayedInMillis);
}
private boolean checkPort(int port) {
if (port < 0 || port > 0xFFFF) {
Logger.e(TAG, "port out of range:" + port);
return false;
}
return true;
}
private boolean checkHost(String hostname) {
if (TextUtils.isEmpty(hostname)) {
Logger.e(TAG, "hostname can't be null");
return false;
}
return true;
}
}

View File

@@ -0,0 +1,139 @@
package com.mogo.cloud.socket.third.core;
import android.content.Context;
import android.text.TextUtils;
import com.mogo.cloud.TelephoneUtil;
import com.zhidao.ptech.connsvr.commom.protocol.MogoCommon;
public class SocketConfig {
public static final String PROTO_VERSION = "1.0.1";
private boolean debug = false;
private Context appContext;
/**Need to be registered by server before it can be applied*/
private String channelId;
private Environment environment;
private MogoCommon.Client client;
private boolean openAnalytics;
/**Customized sn can be set*/
private String sn;
private String uid;
private String token;
private String authPubKey;
private SocketConfig() {
}
public static SocketConfig instance() {
return SingletonHolder.INSTANCE;
}
private final static class SingletonHolder {
private static final SocketConfig INSTANCE = new SocketConfig();
}
public SocketConfig setDebug(boolean debug) {
this.debug = debug;
return this;
}
public boolean isDebug() {
return debug;
}
public SocketConfig setAppContext(Context appContext) {
this.appContext = appContext.getApplicationContext();
return this;
}
public Context getAppContext() {
return appContext;
}
public String getChannelId() {
return channelId;
}
public SocketConfig setChannelId(String channelId) {
this.channelId = channelId;
return this;
}
public MogoCommon.Client getClient() {
return client == null ? MogoCommon.Client.car : client;
}
public SocketConfig setClient(MogoCommon.Client client) {
this.client = client;
return this;
}
public Environment getEnvironment() {
return environment == null ? Environment.release : environment;
}
public SocketConfig setEnvironment(Environment environment) {
this.environment = environment;
return this;
}
public boolean isAnalyticsOpen() {
return openAnalytics;
}
public SocketConfig setOpenAnalytics(boolean openAnalytics) {
this.openAnalytics = openAnalytics;
return this;
}
/**Retrieve sn of current device, and return customized sn first*/
public String getSn() {
return TextUtils.isEmpty(sn) ? TelephoneUtil.getSerialNumber() : sn;
}
/**The third-party device can set a customized sn*/
public SocketConfig setSn(String sn) {
this.sn = sn;
return this;
}
public String getUid() {
return uid;
}
public SocketConfig setUid(String uid) {
this.uid = uid;
return this;
}
public String getToken() {
return token;
}
public SocketConfig setToken(String token) {
this.token = token;
return this;
}
public String getAuthPubKey() {
if(TextUtils.isEmpty(authPubKey)){
authPubKey = SocketConstants.DEFAULT_AUTH_PUB_KEY;
}
return authPubKey;
}
public SocketConfig setAuthPubKey(String authPubKey) {
this.authPubKey = authPubKey;
return this;
}
}

View File

@@ -0,0 +1,22 @@
package com.mogo.cloud.socket.third.core;
public interface SocketConstants {
String TAG = "com.zhidao.socket--->";
/*unit is second*/
int DEFAULT_READER_IDLE_TIME = 0;
/*unit is second*/
int DEFAULT_WRITER_IDLE_TIME = 0;
/*unit is second*/
int DEFAULT_READER_WRITER_IDLE_TIME = 60 * 3;
/*unit is ms*/
long ZERO = 0L;
/*unit is ms*/
long ONE_SECOND = 1000L;
/*unit is ms*/
long ONE_MINUTE = 60 * ONE_SECOND;
String DEFAULT_AUTH_PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLe57ORPgOnBrcWmGac3esB4PtIyI0rAHiyk5QoCRTnTyanwWLfstu7mz2MSHD3YuveNWDiIY8vtRvFNE4M/yA7eb4Mct01VKhKFI/JqwyXgNaSh5YCfmv0vg9687c7IUjTEAg+ReC/bSLDqEB3a0vuP95Txtj9smMlx1e37XFYQIDAQAB";
}

View File

@@ -0,0 +1,18 @@
package com.mogo.cloud.socket.third.core.client;
import io.netty.channel.ChannelHandler;
/**
* Client-side interface to collect all {@link ChannelHandler}. By doing so, we can conveniently
* use {@link ChannelHandlerHolder#handlers()} methods to reconnect to server.
*/
/*package*/ interface ChannelHandlerHolder {
/**
* Collection of {@link ChannelHandler} used for {@link io.netty.bootstrap.Bootstrap#handler(ChannelHandler)}
* to connect server.
*
* @return Collection of {@link ChannelHandler}
*/
ChannelHandler[] handlers();
}

View File

@@ -0,0 +1,210 @@
package com.mogo.cloud.socket.third.core.client;
import android.text.TextUtils;
import com.mogo.cloud.socket.third.analytics.EventRequest;
import com.mogo.cloud.socket.third.analytics.SocketStatus;
import com.mogo.cloud.socket.third.core.CallbackManager;
import com.mogo.cloud.socket.third.core.ConnectionLifecycleListener;
import com.mogo.cloud.socket.third.core.SocketConfig;
import com.mogo.cloud.socket.third.core.SocketConstants;
import com.mogo.cloud.socket.third.utils.LoginStatusUtil;
import com.mogo.cloud.socket.third.utils.RSAUtils;
import com.mogo.cloud.socket.third.utils.RequestUtil;
import com.mogo.cloud.utils.logger.Logger;
import com.zhidao.ptech.connsvr.protocol.MogoConnsvr;
import com.zhidao.ptech.connsvr.protocol.model.MogoConnsvrPacket;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
@ChannelHandler.Sharable
/*package*/ final class ClientChannelReader extends ChannelInboundHandlerAdapter {
public ClientChannelReader() {
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
final IdleStateEvent e = (IdleStateEvent) evt;
switch (e.state()) {
case WRITER_IDLE:
RequestUtil.sendHeartbeat(ctx.channel());
Logger.i(SocketConstants.TAG, "client send heartbeat write-idle");
break;
case READER_IDLE:
RequestUtil.sendHeartbeat(ctx.channel());
Logger.i(SocketConstants.TAG, "client send heartbeat reader-idle");
break;
default:
break;
}
} else {
super.userEventTriggered(ctx, evt);
}
}
@Override
public void channelRead(ChannelHandlerContext channelHandlerContext, Object msg) throws Exception {
if (!(msg instanceof MogoConnsvrPacket)) {
Logger.i(SocketConstants.TAG, "msg is null or msg is not MogoConnsvrPacket type---" + (msg == null ? "" : msg.toString()));
EventRequest.trackException("msg is not instanceof MogoConnsvrPacket");
//重新请求ip port
onRetryLogin();
return;
}
Logger.i(SocketConstants.TAG, "Client---client receive server---" + msg.toString());
final MogoConnsvrPacket mogoConnsvrPacket = (MogoConnsvrPacket) msg;
final MogoConnsvr.MsgType msgType = mogoConnsvrPacket.getMsgType(((MogoConnsvrPacket) msg).getHeaderPb());
Logger.i(SocketConstants.TAG, "receive server---msgType" + msgType.name());
if (msgType == MogoConnsvr.MsgType.mogoMsgTypeConnSvrAuthMidRsp) {
//返回256位随机字符串, 加密后再次发给服务端验证
LoginStatusUtil.setStatus(false);
if (mogoConnsvrPacket.getPayload() == null) {
Logger.i(SocketConstants.TAG, "AuthMidRsp==>Packet.getPayload is null");
EventRequest.trackException("AuthMidRsp==>Packet.getPayload is null");
//重新请求ip port
onRetryLogin();
return;
}
MogoConnsvr.AuthMidRsp authMidRsp = MogoConnsvr.AuthMidRsp.parseFrom(mogoConnsvrPacket.getPayloadBytes());
if (authMidRsp != null && !TextUtils.isEmpty(authMidRsp.getKey())) {
String key = RSAUtils.encryptByPublic(authMidRsp.getKey() + SocketConfig.instance().getSn());
RequestUtil.checkAuth(key);
} else {
EventRequest.trackException("authMidRsp is null or getKey is null");
//重新请求ip port
onRetryLogin();
}
} else if (msgType == MogoConnsvr.MsgType.mogoMsgTypeConnSvrAuthRsp) {
LoginStatusUtil.setStatus(false);
if (mogoConnsvrPacket.getPayload() == null) {
EventRequest.trackException("AuthRsp==> Packet.getPayload is null");
Logger.i(SocketConstants.TAG, "login response ---> response is null");
//重新请求ip port
onRetryLogin();
return;
}
MogoConnsvr.AuthRsp authRsp = MogoConnsvr.AuthRsp.parseFrom(mogoConnsvrPacket.getPayloadBytes());
if (authRsp != null) {
MogoConnsvr.AuthCode authCode = authRsp.getAuthCode();
if (authCode == MogoConnsvr.AuthCode.AUTH_SUCCESS) {
onAuthSuccess(channelHandlerContext.channel());
} else {
EventRequest.trackSocketStatus(SocketStatus.auth_rsp_failed, "auth code is not success");
onRetryLogin();
}
} else {
EventRequest.trackException("AuthRsp==> authRsp is null");
//重新请求ip port
onRetryLogin();
}
} else if (msgType == MogoConnsvr.MsgType.mogoMsgTypeConnSvrAgentInfoRsp) {//用户信息
final MogoConnsvr.ConnSvrUserInfoRsp userInfoResponse = MogoConnsvr.ConnSvrUserInfoRsp.parseFrom(mogoConnsvrPacket.getPayloadBytes());
if (userInfoResponse.getResult()) {
Logger.i(SocketConstants.TAG, "Client receives server's user info response, result is true.");
LoginStatusUtil.setStatus(true);
} else {
EventRequest.trackSocketStatus(SocketStatus.send_userInfo_rsp_failed, "send_userInfo_rsp_failed");
onRetryLogin();
LoginStatusUtil.setStatus(false);
}
} else if (msgType == MogoConnsvr.MsgType.mogoMsgTypeConnSvrDisconnectRsp) {//链接断开
LoginStatusUtil.setStatus(false);
Logger.i(SocketConstants.TAG, "mogoMsgTypeConnSvrDisconnectRsp retry login");
EventRequest.trackSocketStatus(SocketStatus.socket_disconnect, "disconnect");
//重新请求ip port
onRetryLogin();
} else if (msgType == MogoConnsvr.MsgType.mogoMsgTypeAppPushKickMessageReq) {
LoginStatusUtil.setStatus(false);
Logger.i(SocketConstants.TAG, "close channel response ---> 被踢下线");
EventRequest.trackSocketStatus(SocketStatus.socket_disconnect, "kick out, socket is close");
ClientSocketManager.getInstance().close();
} else if (msgType == MogoConnsvr.MsgType.mogoMsgTypeAppPushMessageReq) {//推送消息
if (mogoConnsvrPacket.getPayload() == null) {
Logger.i(SocketConstants.TAG, "push message response is null");
EventRequest.trackException("push payload message response is null");
return;
}
Logger.i(SocketConstants.TAG, "push message response received");
try {
MogoConnsvr.Header header = MogoConnsvr.Header.parseFrom(mogoConnsvrPacket.getHeaderBytes());
if (header != null) {
//收到消息的回执
MogoConnsvr.Header rspHeader = MogoConnsvr.Header.newBuilder(((MogoConnsvrPacket) msg).getHeaderPb())
.setMsgType(MogoConnsvr.MsgType.mogoMsgTypeAppPushMessageRsp_VALUE)
.build();
MogoConnsvrPacket packet = new MogoConnsvrPacket(Unpooled.wrappedBuffer(rspHeader.toByteArray()));
RequestUtil.ack(channelHandlerContext.channel(), packet.getBytes());
String appId = header.getAppId();
long msgId = header.getMsgId();
CallbackManager.getInstance().notify(mogoConnsvrPacket.getPayloadBytes(), appId, msgId);
}
} catch (Exception e) {
e.printStackTrace();
}
} else if (msgType == MogoConnsvr.MsgType.mogoMsgTypeAppUpstreamAck) {
Logger.i(SocketConstants.TAG, "receive message ack");
byte[] bytes = mogoConnsvrPacket.getHeaderBytes();
try {
MogoConnsvr.Header header = MogoConnsvr.Header.parseFrom(bytes);
if (header != null) {
CallbackManager.getInstance().ack(bytes, mogoConnsvrPacket.getPayloadBytes());
}
} catch (Exception e) {
e.printStackTrace();
}
} else if (msgType == MogoConnsvr.MsgType.mogoMsgTypeConnSvrHeartbeatReq) {
Logger.i(SocketConstants.TAG, "Client receives server's heartbeat.");
}
ReferenceCountUtil.release(msg);
}
private void onAuthSuccess(Channel channel) {
Logger.i(SocketConstants.TAG, "Client authority check succeeded");
//send heartbeat.
HeartbeatAlarmManager.getInstance().send();
//send user info
RequestUtil.sendUserInfo(channel);
}
private synchronized void onRetryLogin() {
onConnectFailure();
Logger.i(SocketConstants.TAG, "Client login fails, retry ing");
}
/**
* 重新请求ip port
*/
private void onConnectFailure() {
ConnectionLifecycleListener connectionLifecycleListener = ClientSocketManager.getInstance().getConnectionLifecycleListener();
if (connectionLifecycleListener != null) {
//关闭原有通道,重新请求通道
ClientSocketManager.getInstance().close();
Logger.i(SocketConstants.TAG, "Client onConnectFailure, retry in 5s");
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
EventRequest.trackException(cause.getMessage());
cause.printStackTrace();
ctx.close();
}
}

View File

@@ -0,0 +1,220 @@
package com.mogo.cloud.socket.third.core.client;
import com.mogo.cloud.socket.third.core.ConnectionLifecycleListener;
import com.mogo.cloud.socket.third.core.SocketConstants;
import com.mogo.cloud.socket.third.utils.LoginStatusUtil;
import com.mogo.cloud.socket.third.utils.RequestUtil;
import com.mogo.cloud.utils.logger.Logger;
import com.zhidao.ptech.connsvr.protocol.codec.MogoPacketDecoder;
import com.zhidao.ptech.connsvr.protocol.codec.MogoPacketFrameDecoder;
import com.zhidao.ptech.connsvr.protocol.codec.MogoPacketFrameEncoder;
import com.zhidao.ptech.connsvr.protocol.model.MogoConnsvrPacket;
import java.util.concurrent.TimeUnit;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.AdaptiveRecvByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.HashedWheelTimer;
public class ClientSocketManager {
private final HashedWheelTimer hashedWheelTimer = new HashedWheelTimer();
private final Bootstrap bootstrap = new Bootstrap();
private final NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
private volatile boolean canReconnect = true;
private volatile boolean isConnected = false;
private Channel channel;
private ConnectionLifecycleListener connectionLifecycleListener;
public static ClientSocketManager getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
private static final ClientSocketManager INSTANCE = new ClientSocketManager();
}
private ClientSocketManager() {
initialize();
}
private synchronized void initialize() {
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator.DEFAULT);
bootstrap.group(eventLoopGroup);
final ConnectionWatchdog watchdog = createWatchdog();
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(watchdog.handlers());
}
});
}
public boolean isConnected() {
return isConnected;
}
private synchronized ConnectionWatchdog createWatchdog() {
return new ConnectionWatchdog() {
@Override
public ChannelHandler[] handlers() {
return new ChannelHandler[]{
this,
//decode
new MogoPacketFrameDecoder(MogoPacketFrameDecoder.MAX_FRAME_LENGTH,
MogoPacketFrameDecoder.LENGTH_FIELD_OFFSET,
MogoPacketFrameDecoder.LENGTH_FIELD_SIZE),
new MogoPacketDecoder(),
//encode
new MogoPacketFrameEncoder(),
//config idle state
new IdleStateHandler(SocketConstants.DEFAULT_READER_IDLE_TIME, SocketConstants.DEFAULT_READER_WRITER_IDLE_TIME, SocketConstants.DEFAULT_READER_WRITER_IDLE_TIME, TimeUnit.SECONDS),
//send and receive proto-type data.
new ClientChannelReader(),
};
}
};
}
private synchronized void writeAndFlush(Object msg) {
if (channel == null) {
Logger.i(SocketConstants.TAG, "socket channel is null when write and flush");
return;
}
if (!(msg instanceof MogoConnsvrPacket)) {
Logger.i(SocketConstants.TAG, "msg is not MogoConnsvrPacket type when write and flush.");
return;
}
try {
channel.writeAndFlush(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized Channel getChannel() {
return channel;
}
public synchronized void start(String host, int port) {
if (isConnected) {
Logger.i(SocketConstants.TAG, "do not need to start, channel is connected");
return;
}
canReconnect = true;
isConnected = false;
resetInetAddress(host, port);
doConnection(SocketConstants.ONE_SECOND);
}
public synchronized void setConnectionLifecycleListener(ConnectionLifecycleListener connectionLifecycleListener) {
this.connectionLifecycleListener = connectionLifecycleListener;
}
public synchronized ConnectionLifecycleListener getConnectionLifecycleListener() {
return connectionLifecycleListener;
}
private synchronized void resetInetAddress(String host, int port) {
bootstrap.remoteAddress(host, port);
}
private synchronized void doConnection(long delayInMs) {
if (channel != null && channel.isOpen() && channel.isActive()) {
Logger.i(SocketConstants.TAG, "channel is active, no need to call doConnection(long delayInMs)");
return;
}
hashedWheelTimer.newTimeout(timeout -> {
if (!canReconnect) {
return;
}
final ChannelFuture future = bootstrap.connect();
future.addListener((ChannelFutureListener) future1 -> {
if (future1.isSuccess()) {
Logger.i(SocketConstants.TAG, "Client---connecting server succeeds");
onConnectSuccess(future1.channel());
} else {
Logger.i(SocketConstants.TAG, "Client---connecting server fails失败重试");
Logger.i(SocketConstants.TAG, future1.cause().getMessage());
onConnectFailure();
}
});
}, delayInMs, TimeUnit.MILLISECONDS);
}
private synchronized void onConnectSuccess(Channel channel) {
this.isConnected = true;
this.channel = channel;
RequestUtil.login(channel);
if (connectionLifecycleListener != null) {
connectionLifecycleListener.onConnectSuccess();
}
}
private synchronized void onConnectFailure() {
this.isConnected = false;
close(canReconnect);
if (connectionLifecycleListener != null) {
connectionLifecycleListener.onConnectFailure();
}
}
synchronized void onConnectionLost() {
this.isConnected = false;
close(canReconnect);
if (connectionLifecycleListener != null) {
connectionLifecycleListener.onConnectLost(canReconnect);
}
}
private synchronized void closeChannelSafely() {
try {
if (channel != null) {
channel.close();
channel = null;
Logger.i(SocketConstants.TAG, "channel is null");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized void close() {
close(false);
if (connectionLifecycleListener != null) {
connectionLifecycleListener.onConnectFailure();
}
}
public synchronized void close(boolean allowReconnect) {
//close channel
closeChannelSafely();
//reset status
isConnected = false;
canReconnect = allowReconnect;
LoginStatusUtil.setStatus(false);
HeartbeatAlarmManager.getInstance().cancel();
}
}

View File

@@ -0,0 +1,32 @@
package com.mogo.cloud.socket.third.core.client;
import com.mogo.cloud.socket.third.analytics.EventRequest;
import com.mogo.cloud.socket.third.analytics.SocketStatus;
import com.mogo.cloud.socket.third.core.SocketConstants;
import com.mogo.cloud.utils.logger.Logger;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
@Sharable
/*package*/ abstract class ConnectionWatchdog extends ChannelInboundHandlerAdapter implements ChannelHandlerHolder {
protected ConnectionWatchdog() {
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Logger.i(SocketConstants.TAG, "channel is active");
ctx.fireChannelActive();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Logger.i(SocketConstants.TAG, "channel is inactive, it depends on client's choice whether to reconnect or not.");
EventRequest.trackSocketStatus(SocketStatus.socket_disconnect, "channel is inactive");
ClientSocketManager.getInstance().onConnectionLost();
ctx.fireChannelInactive();
}
}

View File

@@ -0,0 +1,133 @@
package com.mogo.cloud.socket.third.core.client;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import com.mogo.cloud.DevicesUtils;
import com.mogo.cloud.socket.third.analytics.EventRequest;
import com.mogo.cloud.socket.third.analytics.SocketStatus;
import com.mogo.cloud.socket.third.core.SocketConfig;
import com.mogo.cloud.socket.third.core.SocketConstants;
import com.mogo.cloud.socket.third.utils.LoginStatusUtil;
import com.mogo.cloud.socket.third.utils.RequestUtil;
import com.mogo.cloud.utils.logger.Logger;
/**
* Send heartbeats according to network type to keep socket active as well as
* to stop a device falling asleep when the screen is off.
*/
/*package*/ class HeartbeatAlarmManager {
private AlarmManager alarmManager;
private PendingIntent pendingIntent;
private static int lastNetworkType;
private HeartbeatAlarmManager() {
}
public static HeartbeatAlarmManager getInstance() {
return SingletonHolder.INSTANCE;
}
private static final class SingletonHolder {
private static final HeartbeatAlarmManager INSTANCE = new HeartbeatAlarmManager();
}
synchronized void cancel() {
if (alarmManager != null && pendingIntent != null) {
pendingIntent.cancel();
alarmManager.cancel(pendingIntent);
alarmManager = null;
pendingIntent = null;
Logger.i(SocketConstants.TAG, "heartbeat alarm is cancelled");
}
}
synchronized void send() {
this.cancel();
if ((lastNetworkType = DevicesUtils.getNetworkType(SocketConfig.instance().getAppContext())) == ConnectivityManager.TYPE_MOBILE) {
sendHeartbeatRepeatedly(SocketConstants.ONE_MINUTE * 2);
} else {
sendHeartbeatRepeatedly(SocketConstants.ONE_MINUTE * 2);
}
}
/**
* Suggest that interval be 60 seconds or bigger to save power,
* and note that the interval will be set to 60 seconds when the interval is
* small than 60 seconds in or above 5.1{@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}.
*/
private void sendHeartbeatRepeatedly(long interval) {
final Context appContext = SocketConfig.instance().getAppContext();
if (appContext == null) {
Logger.i(SocketConstants.TAG, "sendHeartbeatRepeatedly---> app context is null.");
return;
}
final int requestCode = 1001;
final Intent intent = new Intent(appContext, SendHeartbeatReceiver.class);
alarmManager = (AlarmManager) appContext.getSystemService(Context.ALARM_SERVICE);
pendingIntent = PendingIntent.getBroadcast(
appContext,
requestCode,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
if (DevicesUtils.isSdkHigherThan18()) {
alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + interval,
pendingIntent);
Logger.i(SocketConstants.TAG, "setExact(...)");
} else {
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + interval,
interval,
pendingIntent);
Logger.i(SocketConstants.TAG, "setRepeating(...)");
}
}
public static final class SendHeartbeatReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (!ClientSocketManager.getInstance().isConnected()) {
Logger.i(SocketConstants.TAG, "onReceive--->channel is not connected");
EventRequest.trackSocketStatus(SocketStatus.socket_disconnect, "heartbeat netty socket disconnect");
onRetryConnect();
return;
}
boolean result = LoginStatusUtil.isLogin();
Logger.i(SocketConstants.TAG, "socket connected is : " + result);
//重试逻辑
if (!LoginStatusUtil.isLogin()) {
EventRequest.trackSocketStatus(SocketStatus.socket_disconnect, "heartbeat product socket disconnect");
onRetryConnect();
return;
}
Logger.i(SocketConstants.TAG, "onReceive--->send heartbeat");
RequestUtil.sendHeartbeat(ClientSocketManager.getInstance().getChannel());
if (DevicesUtils.isSdkHigherThan18() || lastNetworkType != DevicesUtils.getNetworkType(SocketConfig.instance().getAppContext())) {
HeartbeatAlarmManager.getInstance().cancel();
HeartbeatAlarmManager.getInstance().send();
}
}
//尝试重新连接
private void onRetryConnect() {
//关闭原有通道,重新请求信通道
ClientSocketManager.getInstance().close();
}
}
}

View File

@@ -0,0 +1,16 @@
package com.mogo.cloud.socket.third.core.network;
import com.elegant.network.BaseResp;
import okhttp3.RequestBody;
import retrofit2.http.Body;
import retrofit2.http.Headers;
import retrofit2.http.POST;
import rx.Observable;
public interface ApiService {
@Headers({"Content-Type:application/json", "Accept:application/json"})
@POST("/connect/message/messageCallback")
Observable<BaseResp> socketMessageCallback(@Body RequestBody requestBody);
}

View File

@@ -0,0 +1,115 @@
package com.mogo.cloud.socket.third.core.network;
import android.content.Context;
import com.elegant.log.simplelog.Logger;
import com.elegant.network.BaseResp;
import com.elegant.network.DefSubscriberImpl;
import com.elegant.network.NetConstants;
import com.elegant.network.ParamsBuilder;
import com.elegant.network.RequestOptions;
import com.elegant.network.utils.GsonUtil;
import com.elegant.network.utils.NetworkSdkUtils;
import com.elegant.utils.CommonUtils;
import com.mogo.cloud.socket.third.core.SocketConfig;
import com.mogo.cloud.socket.third.core.network.model.MessageCallbackData;
import com.mogo.cloud.socket.third.core.network.model.SocketAddressData;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import okhttp3.RequestBody;
public class RequestManager {
private static final String TAG = "RequestManager";
public static void socketMessageCallback(long msgId, String appId) {
final List<Long> msgIds = new ArrayList<>();
msgIds.add(msgId);
MessageCallbackData callbackData = new MessageCallbackData(appId);
callbackData.setNotifyMsgIds(msgIds);
RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),
GsonUtil.jsonFromObject(callbackData));
RequestOptions requestOptions = RequestOptions.of(SocketConfig.instance().getAppContext());
ServiceFactory.newApiService().socketMessageCallback(body).
compose(NetworkSdkUtils.transformer()).
subscribe(new DefSubscriberImpl<BaseResp>(requestOptions) {
@Override
protected void onFailure(int code, String message) {
super.onFailure(code, message);
Logger.d(TAG,"socket message callback failed");
}
@Override
protected void onSuccess(BaseResp o) {
super.onSuccess(o);
Logger.d(TAG,"socket message callback succeeded");
}
@Override
protected void onNetworkLost() {
super.onNetworkLost();
Logger.d(TAG,"request socket message callback, network is not available.");
}
});
}
private static volatile boolean sRequestingAddress = false;
public static void requestSocketAddress(Context context, final SocketAddressCallback socketAddressCallback) {
if (sRequestingAddress) {
return;
}
sRequestingAddress = true;
final Map<String, Object> params = ParamsBuilder.of(false)
.append("lat", 0)//required by server
.append("lon", 0)//required by server
.append("sn", SocketConfig.instance().getSn())
.append("versionCode", CommonUtils.getVersionCode(SocketConfig.instance().getAppContext()))
.append("versionName", CommonUtils.getVersionName(SocketConfig.instance().getAppContext()))
.build();
ServiceFactory.newTechApiService().requestSocketAddress(params)
.compose(NetworkSdkUtils.transformer())
.subscribe(new DefSubscriberImpl<SocketAddressData>(RequestOptions.of(context)) {
@Override
protected void onSuccess(SocketAddressData o) {
super.onSuccess(o);
sRequestingAddress = false;
if (socketAddressCallback != null) {
socketAddressCallback.onGetSocketAddressSuccess(o);
}
}
@Override
protected void onFailure(int code, String message) {
super.onFailure(code, message);
sRequestingAddress = false;
if (socketAddressCallback != null) {
socketAddressCallback.onGetSocketAddressFailed(code, message);
}
}
@Override
protected void onNetworkLost() {
super.onNetworkLost();
sRequestingAddress = false;
if (socketAddressCallback != null) {
socketAddressCallback.onGetSocketAddressFailed(NetConstants.CODE_REQUEST_NO_NETWORK, "网络失败,请检查网络后重试");
}
}
});
}
public interface SocketAddressCallback {
void onGetSocketAddressSuccess(SocketAddressData data);
void onGetSocketAddressFailed(int code, String msg);
}
}

View File

@@ -0,0 +1,44 @@
package com.mogo.cloud.socket.third.core.network;
import com.elegant.network.SimpleServiceFactory;
import com.mogo.cloud.socket.third.core.Environment;
import com.mogo.cloud.socket.third.core.SocketConfig;
public class ServiceFactory extends SimpleServiceFactory {
private static final String TAG = "ServiceFactory";
protected ServiceFactory(){}
public static synchronized ApiService newApiService() {
return newService(getUrl(), ApiService.class);
}
public static synchronized TechApiService newTechApiService() {
return newService(getTechUrl(), TechApiService.class);
}
private static String getTechUrl(){
final Environment environment = SocketConfig.instance().getEnvironment();
if(environment == Environment.release){
return "http://dzt.zhidaozhixing.com";
}else if(environment == Environment.qa){
return "http://dzt-test.zhidaozhixing.com";
}else{
return "http://dzt-dev.zhidaozhixing.com";
}
}
private static String getUrl(){
final Environment environment = SocketConfig.instance().getEnvironment();
if(environment == Environment.release){
return "http://api.zhidaohulian.com/";
}else if(environment == Environment.qa){
return "http://carlife-test.zhidaohulian.com/";
}else{
return "http://carlife-dev.zhidaohulian.com/";
}
}
}

View File

@@ -0,0 +1,15 @@
package com.mogo.cloud.socket.third.core.network;
import com.mogo.cloud.socket.third.core.network.model.SocketAddressData;
import java.util.Map;
import retrofit2.http.GET;
import retrofit2.http.QueryMap;
import rx.Observable;
public interface TechApiService {
@GET("/yycp-conn-admin/connsvrAddr")
Observable<SocketAddressData> requestSocketAddress(@QueryMap Map<String, Object> params);
}

View File

@@ -0,0 +1,38 @@
package com.mogo.cloud.socket.third.core.network.model;
import java.util.List;
import java.util.Random;
public class MessageCallbackData {
private List<Long> notifyMsgIds;
private String reqId;
private String caller;
private long noise;
public MessageCallbackData(String appId) {
this.reqId = getRandomStr();
this.caller = "socketService";
this.noise = System.currentTimeMillis();
}
public void setNotifyMsgIds(List<Long> notifyMsgIds) {
this.notifyMsgIds = notifyMsgIds;
}
private static String getRandomStr() {
char[] c = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
int[] indexArray = new int[32];
Random random = new Random();
for (int i = 0; i < 32; i++) {
indexArray[i] = random.nextInt(36);
}
StringBuffer stringbuffer = new StringBuffer();
for (int i = 0; i < indexArray.length; i++) {
stringbuffer.append(c[indexArray[i]]);
}
return stringbuffer.toString();
}
}

View File

@@ -0,0 +1,15 @@
package com.mogo.cloud.socket.third.core.network.model;
import com.elegant.network.BaseResp;
import java.io.Serializable;
public class SocketAddressData extends BaseResp {
public Address result;
public static class Address implements Serializable {
public String address;
public String ip;
public int port;
}
}

View File

@@ -0,0 +1,21 @@
package com.mogo.cloud.socket.third.core.network.model;
import com.mogo.cloud.GsonUtil;
import org.json.JSONObject;
import java.util.Map;
public class SocketSendData {
public int product_line;
public byte[] payload;
public int header_type;
public String app_id;
public boolean ack;
public long msg_id;
public static SocketSendData parse(Map map) {
JSONObject jsonObject = new JSONObject(map);
return GsonUtil.objectFromJson(jsonObject.toString(), SocketSendData.class);
}
}

View File

@@ -0,0 +1,274 @@
package com.mogo.cloud.socket.third.utils;
public final class Base64Utils {
static private final int BASELENGTH = 128;
static private final int LOOKUPLENGTH = 64;
static private final int TWENTYFOURBITGROUP = 24;
static private final int EIGHTBIT = 8;
static private final int SIXTEENBIT = 16;
static private final int FOURBYTE = 4;
static private final int SIGN = -128;
static private final char PAD = '=';
static private final boolean fDebug = false;
static final private byte[] base64Alphabet = new byte[BASELENGTH];
static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
static {
for (int i = 0; i < BASELENGTH; ++i) {
base64Alphabet[i] = -1;
}
for (int i = 'Z'; i >= 'A'; i--) {
base64Alphabet[i] = (byte) (i - 'A');
}
for (int i = 'z'; i >= 'a'; i--) {
base64Alphabet[i] = (byte) (i - 'a' + 26);
}
for (int i = '9'; i >= '0'; i--) {
base64Alphabet[i] = (byte) (i - '0' + 52);
}
base64Alphabet['+'] = 62;
base64Alphabet['/'] = 63;
for (int i = 0; i <= 25; i++) {
lookUpBase64Alphabet[i] = (char) ('A' + i);
}
for (int i = 26, j = 0; i <= 51; i++, j++) {
lookUpBase64Alphabet[i] = (char) ('a' + j);
}
for (int i = 52, j = 0; i <= 61; i++, j++) {
lookUpBase64Alphabet[i] = (char) ('0' + j);
}
lookUpBase64Alphabet[62] = (char) '+';
lookUpBase64Alphabet[63] = (char) '/';
}
private static boolean isWhiteSpace(char octect) {
return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
}
private static boolean isPad(char octect) {
return (octect == PAD);
}
private static boolean isData(char octect) {
return (octect < BASELENGTH && base64Alphabet[octect] != -1);
}
/**
* Encodes hex octects into Base64
*
* @param binaryData Array containing binaryData
* @return Encoded Base64 array
*/
public static String encode(byte[] binaryData) {
if (binaryData == null) {
return null;
}
int lengthDataBits = binaryData.length * EIGHTBIT;
if (lengthDataBits == 0) {
return "";
}
int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
char encodedData[] = null;
encodedData = new char[numberQuartet * 4];
byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
int encodedIndex = 0;
int dataIndex = 0;
if (fDebug) {
System.out.println("number of triplets = " + numberTriplets);
}
for (int i = 0; i < numberTriplets; i++) {
b1 = binaryData[dataIndex++];
b2 = binaryData[dataIndex++];
b3 = binaryData[dataIndex++];
if (fDebug) {
System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);
}
l = (byte) (b2 & 0x0f);
k = (byte) (b1 & 0x03);
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
if (fDebug) {
System.out.println("val2 = " + val2);
System.out.println("k4 = " + (k << 4));
System.out.println("vak = " + (val2 | (k << 4)));
}
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
}
// form integral number of 6-bit groups
if (fewerThan24bits == EIGHTBIT) {
b1 = binaryData[dataIndex];
k = (byte) (b1 & 0x03);
if (fDebug) {
System.out.println("b1=" + b1);
System.out.println("b1<<2 = " + (b1 >> 2));
}
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
encodedData[encodedIndex++] = PAD;
encodedData[encodedIndex++] = PAD;
} else if (fewerThan24bits == SIXTEENBIT) {
b1 = binaryData[dataIndex];
b2 = binaryData[dataIndex + 1];
l = (byte) (b2 & 0x0f);
k = (byte) (b1 & 0x03);
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
encodedData[encodedIndex++] = PAD;
}
return new String(encodedData);
}
/**
* Decodes Base64 data into octects
*
* @param encoded string containing Base64 data
* @return Array containind decoded data.
*/
public static byte[] decode(String encoded) {
if (encoded == null) {
return null;
}
char[] base64Data = encoded.toCharArray();
// remove white spaces
int len = removeWhiteSpace(base64Data);
if (len % FOURBYTE != 0) {
return null;//should be divisible by four
}
int numberQuadruple = (len / FOURBYTE);
if (numberQuadruple == 0) {
return new byte[0];
}
byte decodedData[] = null;
byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
int i = 0;
int encodedIndex = 0;
int dataIndex = 0;
decodedData = new byte[(numberQuadruple) * 3];
for (; i < numberQuadruple - 1; i++) {
if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))
|| !isData((d3 = base64Data[dataIndex++]))
|| !isData((d4 = base64Data[dataIndex++]))) {
return null;
}//if found "no data" just return null
b1 = base64Alphabet[d1];
b2 = base64Alphabet[d2];
b3 = base64Alphabet[d3];
b4 = base64Alphabet[d4];
decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
}
if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) {
return null;//if found "no data" just return null
}
b1 = base64Alphabet[d1];
b2 = base64Alphabet[d2];
d3 = base64Data[dataIndex++];
d4 = base64Data[dataIndex++];
if (!isData((d3)) || !isData((d4))) {//Check if they are PAD characters
if (isPad(d3) && isPad(d4)) {
if ((b2 & 0xf) != 0)//last 4 bits should be zero
{
return null;
}
byte[] tmp = new byte[i * 3 + 1];
System.arraycopy(decodedData, 0, tmp, 0, i * 3);
tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
return tmp;
} else if (!isPad(d3) && isPad(d4)) {
b3 = base64Alphabet[d3];
if ((b3 & 0x3) != 0)//last 2 bits should be zero
{
return null;
}
byte[] tmp = new byte[i * 3 + 2];
System.arraycopy(decodedData, 0, tmp, 0, i * 3);
tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
return tmp;
} else {
return null;
}
} else { //No PAD e.g 3cQl
b3 = base64Alphabet[d3];
b4 = base64Alphabet[d4];
decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
}
return decodedData;
}
/**
* remove WhiteSpace from MIME containing encoded Base64 data.
*
* @param data the byte array of base64 data (with WS)
* @return the new length
*/
private static int removeWhiteSpace(char[] data) {
if (data == null) {
return 0;
}
// count characters that's not whitespace
int newSize = 0;
int len = data.length;
for (int i = 0; i < len; i++) {
if (!isWhiteSpace(data[i])) {
data[newSize++] = data[i];
}
}
return newSize;
}
}

View File

@@ -0,0 +1,17 @@
package com.mogo.cloud.socket.third.utils;
public final class LoginStatusUtil {
private static volatile boolean loginStatus = false;
private LoginStatusUtil(){}
public synchronized static void setStatus(boolean loginStatus){
LoginStatusUtil.loginStatus = loginStatus;
}
public static boolean isLogin(){
return loginStatus;
}
}

View File

@@ -0,0 +1,126 @@
package com.mogo.cloud.socket.third.utils;
import com.mogo.cloud.socket.third.core.SocketConfig;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
public class RSAUtils {
/**
* 使用私钥解密
*
* @param content 密文
* @param private_key 私钥
* @param input_charset 编码
* @return
* @throws Exception
*/
public static String decrypt(String content, String private_key, String input_charset) throws Exception {
PrivateKey prikey = getPrivateKey(private_key);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, prikey);
InputStream ins = new ByteArrayInputStream(Base64Utils.decode(content));
ByteArrayOutputStream writer = new ByteArrayOutputStream();
byte[] buf = new byte[128];
int bufl;
while ((bufl = ins.read(buf)) != -1) {
byte[] block;
if (buf.length == bufl) {
block = buf;
} else {
block = new byte[bufl];
for (int i = 0; i < bufl; i++) {
block[i] = buf[i];
}
}
writer.write(cipher.doFinal(block));
}
return new String(writer.toByteArray(), input_charset);
}
/**
* 获得私钥
*
* @param key 私钥
* @throws Exception
*/
public static PrivateKey getPrivateKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = Base64Utils.decode(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
/**
* 得到公钥
*
* @param bysKey
* @return
*/
private static PublicKey getPublicKeyFromX509(String bysKey) throws NoSuchAlgorithmException, Exception {
byte[] decodedKey = Base64Utils.decode(bysKey);
X509EncodedKeySpec x509 = new X509EncodedKeySpec(decodedKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(x509);
}
/**
* 使用公钥加密
*
* @param content 明文
* @return
*/
public static String encryptByPublic(String content) {
try {
PublicKey pubicKey = getPublicKeyFromX509(SocketConfig.instance().getAuthPubKey());
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubicKey);
byte plaintext[] = content.getBytes("UTF-8");
int inputLen = plaintext.length;
int offLen = 0;//偏移量
int i = 0;
ByteArrayOutputStream bops = new ByteArrayOutputStream();
while (inputLen - offLen > 0) {
byte[] cache;
if (inputLen - offLen > 117) {
cache = cipher.doFinal(plaintext, offLen, 117);
} else {
cache = cipher.doFinal(plaintext, offLen, inputLen - offLen);
}
bops.write(cache);
i++;
offLen = 117 * i;
}
bops.close();
byte[] encryptedData = bops.toByteArray();
return Base64Utils.encode(encryptedData);
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
}

View File

@@ -0,0 +1,206 @@
package com.mogo.cloud.socket.third.utils;
import android.os.Build;
import android.text.TextUtils;
import com.mogo.cloud.DevicesUtils;
import com.mogo.cloud.TelephoneUtil;
import com.mogo.cloud.socket.third.core.SocketConfig;
import com.mogo.cloud.socket.third.core.SocketConstants;
import com.mogo.cloud.socket.third.core.client.ClientSocketManager;
import com.mogo.cloud.utils.logger.Logger;
import com.zhidao.ptech.connsvr.commom.protocol.MogoCommon;
import com.zhidao.ptech.connsvr.protocol.MogoConnsvr;
import com.zhidao.ptech.connsvr.protocol.model.MogoConnsvrPacket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
public final class RequestUtil {
private RequestUtil() {
}
private static boolean checkNotNull(Channel channel) {
Logger.i(SocketConstants.TAG, channel == null ? "checkNotNull(channel), channel is null." : "checkNotNull(channel), channel is not null.");
boolean isLogin = LoginStatusUtil.isLogin() && ClientSocketManager.getInstance().isConnected();
Logger.i(SocketConstants.TAG, "socket connected is :" + isLogin);
return channel != null;
}
public static void login(Channel channel) {
if (checkNotNull(channel)) {
channel.writeAndFlush(RequestModelUtil.buildAuthRequest());
Logger.i(SocketConstants.TAG, "requestAuth");
}
}
public static void ack(Channel channel, byte[] data) {
if (checkNotNull(channel)) {
channel.writeAndFlush(data);
Logger.i(SocketConstants.TAG, "ack");
}
}
public static void checkAuth(String key) {
Channel channel = ClientSocketManager.getInstance().getChannel();
if (checkNotNull(channel)) {
channel.writeAndFlush(RequestModelUtil.buildEncodeInfo(key));
Logger.i(SocketConstants.TAG, "checkAuth");
}
}
public static void sendHeartbeat(Channel channel) {
if (checkNotNull(channel)) {
channel.writeAndFlush(RequestModelUtil.buildHeartbeat());
Logger.i(SocketConstants.TAG, "send heartbeat");
}
}
public static void sendUserInfo(Channel channel) {
if (checkNotNull(channel)) {
channel.writeAndFlush(RequestModelUtil.buildUserInfo());
Logger.i(SocketConstants.TAG, "send user info");
}
}
/**
* 此app id可被业务随意定制
*/
public static void sendPayloadData(String appId, int productLine, byte[] payload, int headerType, boolean ack, long msgId) {
final Channel channel = ClientSocketManager.getInstance().getChannel();
if (checkNotNull(channel)) {
channel.writeAndFlush(RequestModelUtil.buildPayloadData(productLine, appId, payload, headerType, ack, msgId));
Logger.i(SocketConstants.TAG, "send---> appId is: " + appId + "; headerType is: " + headerType);
}
}
public static final class RequestModelUtil {
private RequestModelUtil() {
}
private static MogoConnsvrPacket buildAuthRequest() {
final ByteBuf headerBuf = Unpooled.buffer();
headerBuf.writeBytes(buildHeader(MogoConnsvr.MsgType.mogoMsgTypeConnSvrAuthReq_VALUE));
return new MogoConnsvrPacket(headerBuf);
}
private static MogoConnsvrPacket buildEncodeInfo(String enInfo) {
final MogoConnsvr.AuthMidReq authMidReq = MogoConnsvr.AuthMidReq.newBuilder()
.setKey(enInfo).build();
final ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(authMidReq.toByteArray());
final ByteBuf headerBuf = Unpooled.buffer();
headerBuf.writeBytes(buildHeader(MogoConnsvr.MsgType.mogoMsgTypeConnSvrAuthMidReq_VALUE));
return new MogoConnsvrPacket(headerBuf, byteBuf);
}
private static ByteBuf buildHeader(int msgType) {
String appId = SocketConfig.instance().getChannelId();
if (TextUtils.isEmpty(appId)) {
appId = "unknown";
}
Logger.i(SocketConstants.TAG, "socket app id is " + appId + ", msg type is " + msgType);
return buildHeader(appId, 0, msgType, false, 0);
}
private static ByteBuf buildHeader(String appId, int productLine, int msgType, boolean ack, long msgId) {
final String token = SocketConfig.instance().getToken();
final String userId = SocketConfig.instance().getUid();
final String sn = SocketConfig.instance().getSn();
final String versionName = DevicesUtils.getVersionName(SocketConfig.instance().getAppContext());
final String fotaVersion = TelephoneUtil.getFotaVersion();
long uid = 0;
try {
if (!TextUtils.isEmpty(userId)) {
uid = Long.parseLong(userId);
}
} catch (Exception e) {
e.printStackTrace();
}
MogoCommon.Client client = SocketConfig.instance().getClient();
if (client == null) {
client = MogoCommon.Client.car;
}
final MogoConnsvr.UserInfo userInfo = MogoConnsvr.UserInfo.newBuilder()
.setUid(uid)
.setToken(TextUtils.isEmpty(token) ? "" : token)
.setClient(client.getNumber())
.setFotaVersion(TextUtils.isEmpty(fotaVersion) ? "" : fotaVersion)
.setAppVersion(TextUtils.isEmpty(versionName) ? "" : versionName)
.setAppVersionCode(DevicesUtils.getVersionCode(SocketConfig.instance().getAppContext()))
.setSn(TextUtils.isEmpty(sn) ? "" : sn).build();
final MogoConnsvr.Header header = MogoConnsvr.Header.newBuilder()
.setTimestamp(System.currentTimeMillis())
.setMsgType(msgType)
.setAck(ack)
.setMsgId(msgId)
.setAppId(appId)
.setUserInfo(userInfo)
.setVersion(0)
.setProductLine(productLine).build();
return Unpooled.buffer().writeBytes(header.toByteArray());
}
private static MogoConnsvrPacket buildHeartbeat() {
return new MogoConnsvrPacket(buildHeader(MogoConnsvr.MsgType.mogoMsgTypeConnSvrHeartbeatReq_VALUE));
}
private static MogoConnsvrPacket buildUserInfo() {
final String versionName = DevicesUtils.getVersionName(SocketConfig.instance().getAppContext());
final String networkTypeName = DevicesUtils.getNetworkTypeName(SocketConfig.instance().getAppContext());
final String sn = SocketConfig.instance().getSn();
long uid = 0;
try {
String userId = SocketConfig.instance().getUid();
if (!TextUtils.isEmpty(userId)) {
uid = Long.parseLong(userId);
}
} catch (Exception e) {
e.printStackTrace();
}
MogoCommon.Client client = SocketConfig.instance().getClient();
if (client == null) {
client = MogoCommon.Client.car;
}
final MogoConnsvr.ConnSvrUserInfoReq userInfoReq = MogoConnsvr.ConnSvrUserInfoReq.newBuilder()
.setUserId(uid)
.setDeviceType(MogoCommon.OS.ANDROID)
.setNettype(TextUtils.isEmpty(networkTypeName) ? "" : networkTypeName)
.setModel(Build.MODEL)
.setManufacturer(Build.MANUFACTURER)
.setBrand(Build.BRAND)
.setAppVersion(TextUtils.isEmpty(versionName) ? "" : versionName)
.setVersion(SocketConfig.PROTO_VERSION)
.setClient(client)
.setSn(TextUtils.isEmpty(sn) ? "" : sn).build();
final ByteBuf payloadBuf = Unpooled.buffer().writeBytes(userInfoReq.toByteArray());
return new MogoConnsvrPacket(buildHeader(MogoConnsvr.MsgType.mogoMsgTypeConnSvrAgentInfoReq_VALUE), payloadBuf);
}
private static MogoConnsvrPacket buildPayloadData(int productLine,
String appId,
byte[] payload,
int headerType,
boolean ack,
long msgId) {
final ByteBuf buf = Unpooled.buffer().writeBytes(payload);
return new MogoConnsvrPacket(buildHeader(appId, productLine, headerType, ack, msgId), buf);
}
}
}

View File

@@ -0,0 +1,40 @@
package com.mogo.cloud.socket.third.utils;
import java.nio.charset.StandardCharsets;
public class SignUtil {
private static final String MD5_PREFIX = "zhidaoautosocket";
private static final char[] DIGITS_LOWER;
static {
DIGITS_LOWER = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
}
public static synchronized String createSign(String token) {
String encryptString = MD5_PREFIX + token;
return encodeHexString(md5(encryptString));
}
private static String encodeHexString(byte[] data) {
return new String(encodeHex(data));
}
private static char[] encodeHex(byte[] data) {
int l = data.length;
char[] out = new char[l << 1];
int i = 0;
for (int var5 = 0; i < l; ++i) {
out[var5++] = DIGITS_LOWER[(240 & data[i]) >>> 4];
out[var5++] = DIGITS_LOWER[15 & data[i]];
}
return out;
}
private static byte[] md5(String string) {
return string == null ? null : string.getBytes(StandardCharsets.UTF_8);
}
}

View File

@@ -2,4 +2,5 @@
package="com.mogo.cloud.common">
/
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

View File

@@ -1,5 +1,11 @@
package com.mogo.cloud;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -33,4 +39,69 @@ public class DevicesUtils {
}
return value;
}
public static String getNetworkTypeName(Context context) {
String typeName = "unknown";
if (context != null) {
ConnectivityManager connectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager == null) {
return typeName;
}
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null) {
typeName = networkInfo.getTypeName();
}
}
return typeName;
}
public static int getNetworkType(Context context) {
if (context != null) {
ConnectivityManager connectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetInfo != null) {
return activeNetInfo.getType();
}
}
}
return -1;
}
public static boolean isSdkHigherThan18() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
}
public static String getVersionName(Context context) {
String appVersion = "";
try {
if (context != null) {
String packageName = context.getApplicationInfo().packageName;
appVersion = context.getPackageManager().getPackageInfo(packageName, 0).versionName;
}
} catch (Exception e) {
e.printStackTrace();
}
return appVersion;
}
public static int getVersionCode(Context context) {
String pkgName = context.getPackageName();
try {
PackageInfo e = context.getPackageManager().getPackageInfo(pkgName, 0);
if (e != null) {
return e.versionCode;
}
} catch (Exception var2) {
var2.printStackTrace();
}
return 1;
}
}

View File

@@ -0,0 +1,82 @@
package com.mogo.cloud;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class SingleThreadPool {
// Thread Pool
private static final int MAX_QUEUE_SIZE = 5000;
private static final int CORE_POOL_SIZE = 1;
private static final int MAX_POOL_SIZE = 1;
private static final int KEEP_ALIEVE_TIME = 5;
private static final TimeUnit UNIT = TimeUnit.SECONDS;
private static final BlockingQueue<Runnable> WORK_QUEUE = new LinkedBlockingQueue<Runnable>(MAX_QUEUE_SIZE);
private static final RejectedExecutionHandler HANDLER = new ThreadPoolExecutor.DiscardPolicy();
// Executor
private ExecutorService mExecutorService;
public SingleThreadPool() {
mExecutorService = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIEVE_TIME, UNIT, WORK_QUEUE, HANDLER);
}
@Override
protected void finalize() throws Throwable {
synchronized (SingleThreadPool.class) {
clearQueue();
shutdown();
}
super.finalize();
}
public void clearQueue() {
if (WORK_QUEUE != null) {
try {
WORK_QUEUE.clear();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public int getPoolSize() {
return WORK_QUEUE == null ? 0 : WORK_QUEUE.size();
}
public boolean isEmpty() {
return WORK_QUEUE == null ? true : WORK_QUEUE.size() == 0 ? true : false;
}
public void shutdown() {
if (mExecutorService != null) {
try {
mExecutorService.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public <T> Future<T> submit(Callable<T> task) {
return mExecutorService.submit(task);
}
public Future<?> submit(Runnable task) {
return mExecutorService.submit(task);
}
public <T> Future<T> submit(Runnable task, T result) {
return mExecutorService.submit(task, result);
}
public void execute(Runnable command) {
mExecutorService.execute(command);
}
}

View File

@@ -0,0 +1,171 @@
package com.mogo.cloud;
import android.content.Context;
import android.net.ConnectivityManager;
import android.os.Build;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import com.mogo.cloud.utils.logger.Logger;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @author wangzhiyuan
* @since 2018/2/7
*/
public class TelephoneUtil {
public static String sn = "";
public static String fotaVersion = "";
public static String fotaDevice = "";
public static String imei = "";
public static String iccid = "";
public static String vin = "";
public static String getFotaDevice() {
if (TextUtils.isEmpty(fotaDevice)) {
String device = "";
try {
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class);
device = (String) get.invoke(c, "ro.fota.device");
if (!TextUtils.isEmpty(device)) {
device = device.trim();
}
} catch (Exception e) {
e.printStackTrace();
}
fotaDevice = device;
}
return fotaDevice;
}
public static String getFotaVersion() {
if (TextUtils.isEmpty(fotaVersion)) {
String version = "";
try {
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class);
version = (String) get.invoke(c, "ro.fota.version");
if (!TextUtils.isEmpty(version)) {
version = version.trim();
}
} catch (Exception e) {
e.printStackTrace();
}
fotaVersion = version;
}
return fotaVersion;
}
public static boolean getMobileDataState(Context context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
// Android 5.0之前
ConnectivityManager conMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Class<?> conMgrClass = null;
Object iConMgr = null;
try {
conMgrClass = Class.forName(conMgr.getClass().getName());//ConnectivityManager
Field iConMgrField = conMgrClass.getDeclaredField("mService");//IConnectivityManager
iConMgrField.setAccessible(true);
iConMgr = iConMgrField.get(conMgr);//获得ConnectivityManager的IConnectivityManager实例
Class<?> iConMgrClass = Class.forName(iConMgr.getClass().getName());
Method getMobileDataEnabledMethod = iConMgrClass.getDeclaredMethod("getMobileDataEnabled");
if (getMobileDataEnabledMethod != null) {
getMobileDataEnabledMethod.setAccessible(true);
boolean result = (Boolean) getMobileDataEnabledMethod.invoke(iConMgr);
Logger.d("TelephoneUtil", "getMobileDataEnabled = " + result);
return result;
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
// Android 5.0之后(包含)
TelephonyManager telephonyService = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
try {
Method getDataEnabled = telephonyService.getClass().getDeclaredMethod("getDataEnabled");
if (null != getDataEnabled) {
boolean result = (Boolean) getDataEnabled.invoke(telephonyService);
Logger.d("TelephoneUtil", "getDataEnabled = " + result);
return result;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
public static void setMobileDataState(Context context, boolean enable) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
// Android 5.0之前
ConnectivityManager conMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Class<?> conMgrClass = null;
Object iConMgr = null;
try {
conMgrClass = Class.forName(conMgr.getClass().getName());//ConnectivityManager
Field iConMgrField = conMgrClass.getDeclaredField("mService");//IConnectivityManager
iConMgrField.setAccessible(true);
iConMgr = iConMgrField.get(conMgr);//获得ConnectivityManager的IConnectivityManager实例
Class<?> iConMgrClass = Class.forName(iConMgr.getClass().getName());
Method setMobileDataEnabledMethod = iConMgrClass.getDeclaredMethod("setMobileDataEnabled", boolean.class);
if (setMobileDataEnabledMethod != null) {
setMobileDataEnabledMethod.setAccessible(true);
setMobileDataEnabledMethod.invoke(iConMgr, enable);
Logger.d("TelephoneUtil", "setMobileDataEnabled = " + enable);
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
// Android 5.0之后(包含)
try {
TelephonyManager telephonyService = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
Method setDataEnabledMethod = telephonyService.getClass().getDeclaredMethod("setDataEnabled", boolean.class);
if (null != setDataEnabledMethod) {
setDataEnabledMethod.invoke(telephonyService, enable);
Logger.d("TelephoneUtil", "setDataEnabled = " + enable);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static String getSerialNumber() {
if (TextUtils.isEmpty(sn)) {
String serial = "";
try {
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class);
serial = (String) get.invoke(c, "zhidao.serial");
if (TextUtils.isEmpty(serial)) {
serial = (String) get.invoke(c, "gsm.serial");
}
if (TextUtils.isEmpty(serial)) {
serial = (String) get.invoke(c, "ro.serialno");
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (serial.startsWith("ZD") || serial.startsWith("XT")) {
sn = serial;
} else {
return serial;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return sn;
}
}

View File

@@ -36,22 +36,22 @@ PASSWORD=xintai2018
RELEASE=true
# AI CLOUD 云平台
# 工具类
MOGO_UTILS_VERSION=1.1.56-live
MOGO_UTILS_VERSION=1.2.2
# 网络请求
MOGO_NETWORK_VERSION=1.1.56-live
MOGO_NETWORK_VERSION=1.2.2
# 网络DNS
MOGO_HTTPDNS_VERSION=1.1.56-live
MOGO_HTTPDNS_VERSION=1.2.2
# 鉴权
MOGO_PASSPORT_VERSION=1.1.56-live
MOGO_PASSPORT_VERSION=1.2.2
# 常链接
MOGO_SOCKET_VERSION=1.1.56-live
MOGO_SOCKET_VERSION=1.2.2
# 数据采集
MOGO_REALTIME_VERSION=1.1.56-live
MOGO_REALTIME_VERSION=1.2.2
# 探路,道路事件发布,获取
MOGO_TANLU_VERSION=1.1.56-live
MOGO_TANLU_VERSION=1.2.2
# 直播推流
MOGO_LIVE_VERSION=1.1.56-live
MOGO_LIVE_VERSION=1.2.2
# 直播拉流
MOGO_TRAFFICLIVE_VERSION=1.1.56-live
MOGO_TRAFFICLIVE_VERSION=1.2.2
# 定位服务
MOGO_LOCATION_VERSION=1.1.56-live
MOGO_LOCATION_VERSION=1.2.2