package com.hdl.sdk.connect.protocol;
|
|
|
import android.os.Build;
|
import android.text.TextUtils;
|
import android.util.Log;
|
|
import androidx.annotation.RequiresApi;
|
|
import com.google.gson.reflect.TypeToken;
|
import com.hdl.sdk.common.config.TopicConstant;
|
import com.hdl.sdk.common.event.EventDispatcher;
|
import com.hdl.sdk.common.exception.HDLLinkException;
|
import com.hdl.sdk.common.utils.ByteUtils;
|
import com.hdl.sdk.common.utils.LogUtils;
|
import com.hdl.sdk.common.utils.SPUtils;
|
import com.hdl.sdk.common.utils.gson.GsonConvert;
|
import com.hdl.sdk.connect.HDLLink;
|
import com.hdl.sdk.connect.bean.LinkResponse;
|
import com.hdl.sdk.connect.bean.request.AuthenticateRequest;
|
import com.hdl.sdk.connect.bean.response.DeviceDeleteResponse;
|
import com.hdl.sdk.connect.bean.response.DeviceInfoResponse;
|
import com.hdl.sdk.connect.callback.HDLLinkCallBack;
|
import com.hdl.sdk.connect.config.HDLLinkConfig;
|
import com.hdl.sdk.connect.socket.HDLAuthSocket;
|
import com.hdl.sdk.connect.socket.HDLSocket;
|
import com.hdl.sdk.connect.utils.AesUtil;
|
import com.hdl.sdk.socket.codec.ByteToMessageDecoder;
|
|
import java.util.ArrayList;
|
import java.util.List;
|
|
import android.util.Base64;
|
|
import kotlin.ParameterName;
|
|
/**
|
* Created by Tong on 2021/9/22.
|
* link协议粘包拆包
|
*/
|
public class LinkMessageDecoder extends ByteToMessageDecoder<LinkResponse> {
|
|
private final List<Byte> bytes;
|
|
private final byte[] head = "Topic:".getBytes();
|
// private final byte[] body = "\r\n\r\n".getBytes();
|
|
public LinkMessageDecoder() {
|
this.bytes = new ArrayList<>();
|
}
|
|
/// <summary>
|
/// 获取内容长度
|
/// </summary>
|
/// <param name="topMsgs"></param>
|
/// <returns></returns>
|
int getLenght(String[] topMsgs) {
|
for (int i = 0; i < topMsgs.length; i++) {
|
String topMsg = topMsgs[i].trim();
|
if (topMsg.startsWith("Length:")) {
|
return Integer.parseInt(topMsg.replace("Length:", ""));
|
}
|
}
|
//找不到长度
|
return -1;
|
}
|
|
/// <summary>
|
/// 获取主题
|
/// </summary>
|
/// <param name="topMsgs"></param>
|
/// <returns></returns>
|
private String getTopic(String[] topMsgs) {
|
for (int i = 0; i < topMsgs.length; i++) {
|
String topMsg = topMsgs[i].trim();
|
if (topMsg.startsWith("Topic:")) {
|
return topMsg.replace("Topic:", "");
|
}
|
}
|
//找不到主题
|
return null;
|
}
|
|
/**
|
* 获取数据的开始位置
|
*
|
* @param arrayList 接收到的所有数据
|
* @return 数据位的开始索引
|
*/
|
int getDataIndex(List<Byte> arrayList) {
|
byte r = (byte) '\r';
|
byte n = (byte) '\n';
|
for (int i = 0; i < arrayList.size(); i++) {
|
//找出数据内容前面的两个换行
|
if (3 <= i && arrayList.get(i - 3) == r && arrayList.get(i - 2) == n && arrayList.get(i - 1) == r && arrayList.get(i) == n) {
|
//剩余的数据
|
return i + 1;
|
}
|
}
|
return -1;
|
}
|
|
void initReceiveData(List<Byte> list) {
|
|
int index = 0;
|
boolean isMatch = false;
|
for (; index < list.size() - head.length; index++) {
|
isMatch = true;
|
for (int j = 0, k = 0; j < head.length; j++, k++) {
|
if (head[j] != list.get(index + k)) {
|
isMatch = false;
|
break;
|
}
|
}
|
if (isMatch) {
|
break;
|
}
|
}
|
|
if (0 < index && isMatch) {
|
List<Byte> tempList = new ArrayList<Byte>();
|
for (int i = index; i < list.size(); i++) {
|
tempList.add(list.get(i));
|
}
|
|
list.clear();
|
for (int i = 0; i < tempList.size(); i++) {
|
list.add(tempList.get(i));
|
}
|
}
|
}
|
|
|
@RequiresApi(api = Build.VERSION_CODES.O)
|
@Override
|
protected synchronized LinkResponse decoder(Object msg, String ipaddress) throws Exception {
|
if (msg instanceof byte[]) {
|
bytes.addAll(ByteUtils.toByteList((byte[]) msg));
|
//如果多条命令打包在一条数据中,都需要处理完
|
while (true) {
|
initReceiveData(bytes);
|
byte[] recevieBytes = ByteUtils.toByteArray(bytes);
|
String data = new String(recevieBytes);
|
|
String[] topMsgs = data.split("\r\n");
|
|
String topic = getTopic(topMsgs);
|
if (topic == null) {
|
break;
|
}
|
|
int lenght = getLenght(topMsgs);
|
|
if (lenght <= 0) {
|
//头部数据还没有接收完成
|
break;
|
}
|
//是否已经获取完整所有的数据
|
byte[] body = new byte[lenght];
|
int index = getDataIndex(bytes);
|
if (bytes.size() < index + lenght) {
|
//当前数据还没有接收完成
|
break;
|
}
|
//复制出body数据
|
System.arraycopy(recevieBytes, index, body, 0, body.length);
|
|
//保留剩余的数据,以次用
|
bytes.clear();
|
for (int i = index + lenght; i < recevieBytes.length; i++) {
|
bytes.add(recevieBytes[i]);
|
}
|
LinkResponse response = new LinkResponse();
|
response.setSource_ipAddress(ipaddress);
|
response.setTopic(topic);
|
if (HDLLinkConfig.getInstance().ifNeedEncrypt(response.getTopic())) {
|
//需要解密
|
byte[] bodyBytes = AesUtil.aesDecrypt(body, HDLLinkConfig.getInstance().getLocalSecret());
|
if (bodyBytes != null) {
|
body = bodyBytes;
|
} else {
|
try {
|
//之前的版本这块是明文的
|
if (!topic.contains("heartbeat_reply")) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
LogUtils.e("解密失败,数据内容是:\r\n" + Base64.encodeToString(body, Base64.NO_WRAP));
|
else {
|
LogUtils.e("解密失败,数据内容是:\r\n" + new String(body, "utf-8"));
|
}
|
}
|
} catch (Exception e) {
|
}
|
}
|
}
|
|
String bodyString = new String(body, "utf-8");
|
response.setData(bodyString);
|
LogUtils.i("接收到数据:" + response.getTopic() + "\r\n" + response.getData());
|
|
String updateLocalSecret = String.format(TopicConstant.LINK_BROADCAST, HDLLinkConfig.getInstance().getGatewayId());
|
String deleteNetwork = "";
|
if (HDLLinkConfig.getInstance().getDeviceInfoBean() != null) {
|
deleteNetwork = String.format(TopicConstant.DELETE_NOTIFY, HDLLinkConfig.getInstance().getDeviceInfoBean().getOID());
|
}
|
|
if (response.getTopic().equals("/user/all/custom/gateway/search")) {
|
HDLAuthSocket.getInstance().UploadGatewayInfo(new HDLLinkCallBack() {
|
@Override
|
public void onSuccess(String msg) {
|
LogUtils.i("UploadGatewayInfo onSucceed");
|
}
|
|
@Override
|
public void onError(HDLLinkException e) {
|
LogUtils.i("UploadGatewayInfo onError");
|
}
|
});
|
} else if (response.getTopic().equals(updateLocalSecret) || response.getTopic().equals(TopicConstant.LINK_BROADCAST)) {
|
try {
|
DeviceInfoResponse deviceInfoResponse = GsonConvert.getGson().fromJson(response.getData(), new TypeToken<DeviceInfoResponse>() {
|
}.getType());
|
|
if (!TextUtils.isEmpty(deviceInfoResponse.getObjects().getLocalSecret())) {
|
byte[] baseBytes = Base64.decode(deviceInfoResponse.getObjects().getLocalSecret(), Base64.NO_WRAP);
|
String mackey = "";
|
if (!TextUtils.isEmpty(SPUtils.getString("auth_mackey_key", ""))) {
|
mackey = SPUtils.getString("auth_mackey_key", "");
|
byte[] bodyBytes = AesUtil.aesDecrypt(baseBytes, mackey.substring(mackey.length() - 16));
|
String localSecret = new String(bodyBytes, "utf-8");
|
Log.d("panlili", "更新密钥----->localSecret= " + localSecret);
|
HDLLinkConfig.getInstance().setLocalSecret(localSecret);
|
}
|
}
|
} catch (Exception e) {
|
LogUtils.i("LinkMessageDecoder.java:getLocalSecret----->e= " + e.getMessage());
|
}
|
} else if (response.getTopic().equals(deleteNetwork)) {
|
try {
|
DeviceDeleteResponse deviceDeleteResponse = GsonConvert.getGson().fromJson(response.getData(), new TypeToken<DeviceDeleteResponse>() {
|
}.getType());
|
HDLSocket.getInstance().deleteNetwork(deviceDeleteResponse.getObjects().get(0).getOID(), new HDLLinkCallBack() {
|
@Override
|
public void onSuccess(String msg) {
|
LogUtils.i("deleteNetwork onSucceed");
|
if (HDLLink.getInstance().listener != null) {
|
HDLLink.getInstance().listener.onSuccess(msg);
|
}
|
}
|
|
@Override
|
public void onError(HDLLinkException e) {
|
LogUtils.i("deleteNetwork onError");
|
if (HDLLink.getInstance().listener != null) {
|
HDLLink.getInstance().listener.onFailure();
|
}
|
}
|
});
|
} catch (Exception e) {
|
LogUtils.i("LinkMessageDecoder.java:deleteNetwork----->e= " + e.getMessage());
|
}
|
}
|
|
//非正常数据,返回
|
if (!((bodyString.startsWith("{") && bodyString.endsWith("}"))
|
|| (bodyString.startsWith("[") && bodyString.endsWith("]")))) {
|
continue;
|
}
|
//解析完成,topic发送一次
|
EventDispatcher.getInstance().post(response.getTopic(), response);
|
}
|
return null;
|
|
}
|
return null;
|
}
|
}
|