add socketModule
This commit is contained in:
2
.idea/gradle.xml
generated
2
.idea/gradle.xml
generated
@@ -16,6 +16,7 @@
|
||||
<option value="$PROJECT_DIR$/foudations/mogo-commons" />
|
||||
<option value="$PROJECT_DIR$/foudations/mogo-httpdns" />
|
||||
<option value="$PROJECT_DIR$/foudations/mogo-passport" />
|
||||
<option value="$PROJECT_DIR$/foudations/mogo-socket" />
|
||||
<option value="$PROJECT_DIR$/modules" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-realtime" />
|
||||
<option value="$PROJECT_DIR$/modules/mogo-tanlu" />
|
||||
@@ -23,6 +24,7 @@
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
<option name="useQualifiedModuleNames" value="true" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
|
||||
1
foudations/mogo-socket/.gitignore
vendored
Normal file
1
foudations/mogo-socket/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
38
foudations/mogo-socket/build.gradle
Normal file
38
foudations/mogo-socket/build.gradle
Normal file
@@ -0,0 +1,38 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.android.compileSdkVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.android.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.android.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
// 长链
|
||||
implementation 'com.zhidao.socket:built-in-socket:1.0.17'
|
||||
// 上报位置
|
||||
implementation 'com.zhidao.locupload:loc-upload-sdk:1.1.7'
|
||||
implementation project(path: ':foudations:mogo-passport')
|
||||
api rootProject.ext.dependencies.mogoutils
|
||||
}
|
||||
|
||||
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()
|
||||
0
foudations/mogo-socket/consumer-rules.pro
Normal file
0
foudations/mogo-socket/consumer-rules.pro
Normal file
4
foudations/mogo-socket/gradle.properties
Normal file
4
foudations/mogo-socket/gradle.properties
Normal file
@@ -0,0 +1,4 @@
|
||||
GROUP=com.mogo.cloud
|
||||
POM_ARTIFACT_ID=socket
|
||||
VERSION_CODE=1
|
||||
VERSION_NAME=1.0.0
|
||||
21
foudations/mogo-socket/proguard-rules.pro
vendored
Normal file
21
foudations/mogo-socket/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.mogo.cloud.socket;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
assertEquals("com.mogo.cloud.socket.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
5
foudations/mogo-socket/src/main/AndroidManifest.xml
Normal file
5
foudations/mogo-socket/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.cloud.socket">
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.mogo.cloud.socket;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
|
||||
/**
|
||||
* socket 长链
|
||||
*/
|
||||
public interface IMogoCloudSocketManager {
|
||||
|
||||
/**
|
||||
* 初始化,各模块不用关心
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param appId 一般为包名,不参与通道的建立,一般用于发消息
|
||||
*/
|
||||
void init(Context context, String appId);
|
||||
|
||||
/**
|
||||
* 注册消息监听
|
||||
*
|
||||
* @param msgType 消息类型
|
||||
* @param listener 回调
|
||||
*/
|
||||
void registerOnMessageListener(int msgType, IMogoCloudSocketOnMessageListener listener);
|
||||
|
||||
/**
|
||||
* 注销消息监听
|
||||
*
|
||||
* @param msgType 消息类型
|
||||
* @param listener 回调
|
||||
*/
|
||||
void unregisterOnMessageListener(int msgType, IMogoCloudSocketOnMessageListener listener);
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @param body 消息体
|
||||
* @param listener 回执监听
|
||||
*/
|
||||
void sendMsg(MsgBody body, IMogoCloudSocketMsgAckListener listener);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.mogo.cloud.socket;
|
||||
|
||||
/**
|
||||
* 消息回执监听
|
||||
*/
|
||||
public interface IMogoCloudSocketMsgAckListener {
|
||||
|
||||
/**
|
||||
* 长连接消息回执
|
||||
* msgId: 消息id
|
||||
*/
|
||||
void onAck(long msgId);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.mogo.cloud.socket;
|
||||
|
||||
/**
|
||||
* 消息回调
|
||||
*/
|
||||
public interface IMogoCloudSocketOnMessageListener<T> {
|
||||
|
||||
Class<T> target();
|
||||
|
||||
void onMsgReceived(T obj);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.mogo.cloud.socket;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
public class MsgBody {
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
private int mMsgType;
|
||||
|
||||
/**
|
||||
* 是否回执
|
||||
*/
|
||||
private boolean mAck = false;
|
||||
|
||||
/**
|
||||
* 消息ID
|
||||
*/
|
||||
private final long mMsgId = System.currentTimeMillis();
|
||||
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
private Object mContent;
|
||||
|
||||
public MsgBody msgType(int msgType) {
|
||||
this.mMsgType = msgType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MsgBody ack(boolean ack) {
|
||||
this.mAck = ack;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MsgBody content(Object object) {
|
||||
this.mContent = object;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMsgType() {
|
||||
return mMsgType;
|
||||
}
|
||||
|
||||
public boolean isAck() {
|
||||
return mAck;
|
||||
}
|
||||
|
||||
public long getMsgId() {
|
||||
return mMsgId;
|
||||
}
|
||||
|
||||
public Object getContent() {
|
||||
return mContent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package com.mogo.cloud.socket;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClient;
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig;
|
||||
import com.mogo.utils.logger.Logger;
|
||||
import com.mogo.utils.network.utils.GsonUtil;
|
||||
import com.zhidao.locupload.Platform;
|
||||
import com.zhidao.ptech.connsvr.protocol.MogoConnsvr;
|
||||
import com.zhidao.socket.Callback;
|
||||
import com.zhidao.socket.CallbackManager;
|
||||
import com.zhidao.socket.Environment;
|
||||
import com.zhidao.socket.SocketClient;
|
||||
import com.zhidao.socket.SocketConfig;
|
||||
import com.zhidao.socket.utils.RequestUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class SocketManager implements IMogoCloudSocketManager, Callback {
|
||||
|
||||
private static final String TAG = "SocketManager";
|
||||
private static volatile SocketManager mInstance;
|
||||
private MoGoAiCloudClientConfig cloudClientConfig;
|
||||
private String mAppId;
|
||||
|
||||
private SocketManager() {
|
||||
CallbackManager.getInstance().register(this);
|
||||
cloudClientConfig = MoGoAiCloudClient.getInstance().getAiCloudClientConfig();
|
||||
}
|
||||
|
||||
public static SocketManager getInstance() {
|
||||
if (mInstance == null) {
|
||||
synchronized (SocketManager.class) {
|
||||
if (mInstance == null) {
|
||||
mInstance = new SocketManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理消息分发
|
||||
* <p>
|
||||
* key - msgType
|
||||
*/
|
||||
private Map<Integer, List<IMogoCloudSocketOnMessageListener>> mListeners = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 管理消息回执
|
||||
* <p>
|
||||
* key - msgId
|
||||
*/
|
||||
private Map<Long, IMogoCloudSocketMsgAckListener> mAckListeners = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
public static final int MAX_CAP = 64; //保证充足的容量应对非常延时的推送
|
||||
private final ArrayList<Long> mReceivedMsgId = new ArrayList<>(MAX_CAP);
|
||||
private int mCurrentIndex = 0;
|
||||
|
||||
@Override
|
||||
public void init(Context context, String appId) {
|
||||
mAppId = appId;
|
||||
SocketConfig.instance()
|
||||
.setAppContext(context.getApplicationContext())
|
||||
.setEnvironment(getEnvironment())
|
||||
.setClient(Platform.getClient(Platform.car))
|
||||
.setChannelId(SocketServicesConstants.SOCKET_CHANNEL_ID)
|
||||
.setOpenAnalytics(true)
|
||||
.setSn(cloudClientConfig.getSn())
|
||||
.setDebug(cloudClientConfig.isShowDebugLog());
|
||||
SocketClient.getInstance().start(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerOnMessageListener(int msgType, IMogoCloudSocketOnMessageListener listener) {
|
||||
if (mListeners.containsKey(msgType)) {
|
||||
Logger.w(TAG, "msgType %d is exist.", msgType);
|
||||
}
|
||||
if (!mListeners.containsKey(msgType)) {
|
||||
mListeners.put(msgType, new ArrayList<>());
|
||||
}
|
||||
mListeners.get(msgType).add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterOnMessageListener(int msgType, IMogoCloudSocketOnMessageListener listener) {
|
||||
if (listener == null) {
|
||||
return;
|
||||
}
|
||||
if (!mListeners.containsKey(msgType)) {
|
||||
return;
|
||||
}
|
||||
List<IMogoCloudSocketOnMessageListener> listeners = mListeners.get(msgType);
|
||||
if (listeners != null) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMsg(MsgBody body, IMogoCloudSocketMsgAckListener listener) {
|
||||
Logger.d(TAG, "sendMsg.");
|
||||
final byte[] pb = convertToPBBytes(body.getMsgType(), objectToBytes(body.getContent()));
|
||||
RequestUtil.sendPayloadData(mAppId, 2, pb, 1, true, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NonNull CallbackManager manager, @NonNull byte[] message, String appId, long msgId) {
|
||||
try {
|
||||
MogoConnsvr.Payload payload = MogoConnsvr.Payload.parseFrom(message);
|
||||
int msgType = payload.getMsgType();
|
||||
Logger.d(TAG, "received msg type = %d", msgType);
|
||||
List<IMogoCloudSocketOnMessageListener> listeners = mListeners.get(msgType);
|
||||
if (listeners != null && !listeners.isEmpty()) {
|
||||
Iterator<IMogoCloudSocketOnMessageListener> iterator = listeners.iterator();
|
||||
if (msgId != 0) { //兼容老版本
|
||||
if (mReceivedMsgId.contains(msgId)) { // 避免消息重发
|
||||
return;
|
||||
}
|
||||
cacheLastReceivedMsgId(msgId);
|
||||
}
|
||||
Object object = null;
|
||||
while (iterator.hasNext()) {
|
||||
IMogoCloudSocketOnMessageListener listener = iterator.next();
|
||||
if (object == null) {
|
||||
object = GsonUtil.objectFromJson(payload.getPayload().toStringUtf8(), listener.target());
|
||||
}
|
||||
if (listener != null) {
|
||||
Logger.d(TAG, "received msgId = %s, content = %s", msgId, payload.getPayload().toStringUtf8());
|
||||
listener.onMsgReceived(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
Logger.e(TAG, e, "parse msg error.");
|
||||
}
|
||||
}
|
||||
|
||||
private void cacheLastReceivedMsgId(long msgId) {
|
||||
if (msgId == 0) {
|
||||
return;
|
||||
}
|
||||
synchronized (this) {
|
||||
mReceivedMsgId.add(mCurrentIndex % MAX_CAP, msgId);
|
||||
mCurrentIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAck(@NonNull CallbackManager manager, @NonNull byte[] headerBytes, byte[] content) {
|
||||
try {
|
||||
MogoConnsvr.Header header = MogoConnsvr.Header.parseFrom(headerBytes);
|
||||
int msgType = header.getMsgType();
|
||||
String appId = header.getAppId();
|
||||
int productLine = header.getProductLine();
|
||||
long msgId = header.getMsgId();
|
||||
IMogoCloudSocketMsgAckListener listener = mAckListeners.remove(msgId);
|
||||
if (listener != null) {
|
||||
listener.onAck(msgId);
|
||||
}
|
||||
Logger.d(TAG, "send message success: msgType = %d, appId = %s, productLine = %d", msgType, appId, productLine);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private Environment getEnvironment() {
|
||||
switch (cloudClientConfig.getNetMode()) {
|
||||
case 1:
|
||||
return Environment.dev;
|
||||
case 2:
|
||||
case 4:
|
||||
return Environment.qa;
|
||||
case 3:
|
||||
default:
|
||||
return Environment.release;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] objectToBytes(Object obj) {
|
||||
String jsonStr = GsonUtil.jsonFromObject(obj);
|
||||
return jsonStr.getBytes();
|
||||
}
|
||||
|
||||
private byte[] convertToPBBytes(int msgType, byte[] payloadBytes) {
|
||||
MogoConnsvr.Payload payloadData = MogoConnsvr.Payload.newBuilder()
|
||||
.setMsgType(msgType)
|
||||
.setPayload(ByteString.copyFrom(payloadBytes)).build();
|
||||
return payloadData.toByteArray();
|
||||
}
|
||||
|
||||
public synchronized void release() {
|
||||
mListeners.clear();
|
||||
mListeners = null;
|
||||
cloudClientConfig = null;
|
||||
mInstance = null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.mogo.cloud.socket;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
public class SocketServicesConstants {
|
||||
|
||||
/**
|
||||
* 建立长链的通道ID
|
||||
*/
|
||||
@Keep
|
||||
public static final String SOCKET_CHANNEL_ID = "dataCrawler";
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.mogo.cloud.socket;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
include ':modules:mogo-realtime'
|
||||
include ':foudations:mogo-socket'
|
||||
include ':modules:mogo-realtime'
|
||||
include ':modules:realtime'
|
||||
include ':modules:mogo-tanlu'
|
||||
|
||||
Reference in New Issue
Block a user