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 { private final List bytes; private final byte[] head = "Topic:".getBytes(); // private final byte[] body = "\r\n\r\n".getBytes(); public LinkMessageDecoder() { this.bytes = new ArrayList<>(); } /// /// 获取内容长度 /// /// /// 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; } /// /// 获取主题 /// /// /// 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 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 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 tempList = new ArrayList(); 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() { }.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() { }.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; } }