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); Log.d("panlili", "----->source_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()); //非正常数据,返回 if (!((bodyString.startsWith("{") && bodyString.endsWith("}")) || (bodyString.startsWith("[") && bodyString.endsWith("]")))) { continue; } //解析完成,topic发送一次 EventDispatcher.getInstance().post(response.getTopic(), response); } return null; } return null; } }