package com.hdl.sdk.connect.socket; import android.text.TextUtils; import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; import com.hdl.sdk.common.event.EventDispatcher; import com.hdl.sdk.common.event.EventListener; import com.hdl.sdk.common.exception.HDLLinkCode; import com.hdl.sdk.common.exception.HDLLinkException; import com.hdl.sdk.common.utils.LogUtils; import com.hdl.sdk.common.utils.ThreadToolUtils; import com.hdl.sdk.connect.HDLLink; import com.hdl.sdk.connect.bean.response.AuthenticateResponse; import com.hdl.sdk.connect.bean.response.NetworkAccessBroadcastResponse; import com.hdl.sdk.connect.callback.BaseCallBack; import com.hdl.sdk.connect.callback.HDLLinkCallBack; import com.hdl.sdk.connect.callback.HDLLinkResponseCallBack; import com.hdl.sdk.connect.config.HDLLinkConfig; import com.hdl.sdk.common.config.TopicConstant; import com.hdl.sdk.common.utils.IdUtils; import com.hdl.sdk.common.utils.IpUtils; import com.hdl.sdk.common.utils.gson.GsonConvert; import com.hdl.sdk.connect.bean.request.AuthenticateRequest; import com.hdl.sdk.connect.bean.response.BaseLocalResponse; import com.hdl.sdk.connect.bean.request.DeviceControlRequest; import com.hdl.sdk.connect.bean.response.GatewaySearchBean; import com.hdl.sdk.connect.bean.LinkRequest; import com.hdl.sdk.connect.bean.LinkResponse; import com.hdl.sdk.connect.protocol.LinkMessageDecoder; import com.hdl.sdk.connect.protocol.LinkMessageEncoder; import com.hdl.sdk.socket.client.UdpClient; import com.hdl.sdk.socket.codec.MessagePipeLine; import com.hdl.sdk.socket.udp.UdpSocketBoot; import com.hdl.sdk.socket.udp.UdpSocketOptions; import java.net.InetSocketAddress; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import static com.hdl.sdk.common.config.TopicConstant.DEIVCE_AUTH_REQUEST; /** * Created by jlchen on 11/11/21. * * @Description : HDLAuthSocket 由于前期已经命名好,不做更改,可用作Udp服务端使用 */ public class HDLAuthSocket { private static final String TAG = "HDLAuth"; /** * udp默认端口 */ private static final int UDP_PORT = 8585; /** * 因为考虑到使用一个端口,要支持接收多网关的数据,所以只允许使用一个 */ private static UdpSocketBoot udpSocketBoot; // private EventListener authEvent; //搜索网关 private EventListener searchGatewayEvent; /** * udp默认组播ip */ private static final String UDP_GROUP_IP = "239.0.168.188"; /** * instance */ private static final HDLAuthSocket instance=new HDLAuthSocket(); private HDLAuthSocket() { initListenerGatewayEvent(); initSearchGatewayEvent(); } // public interface CallBack extends BaseCallBack { // void onSuccess(String msg); // } /** * getInstance * * @return HDLAuthSocket */ public static HDLAuthSocket getInstance() { // if (instance == null) { // synchronized (HDLAuthSocket.class) { // if (instance == null) { // instance = new HDLAuthSocket(); // } // } // } return instance; } private UdpSocketOptions getUdpOptions() { final UdpSocketOptions options = new UdpSocketOptions(); final MessagePipeLine pipeLine = new MessagePipeLine(); pipeLine.add(new LinkMessageDecoder()); pipeLine.add(new LinkMessageEncoder()); options.setHandleMessage(pipeLine); return options; } /** * 获取当前udp对象,如果不存在就创建 * * @return 返回当前对象 */ private synchronized UdpSocketBoot getUdpBoot() { try { if (udpSocketBoot == null) { udpSocketBoot = UdpClient.init(UDP_PORT, getUdpOptions()); udpSocketBoot.bind(); } } catch (Exception e) { // return null; } return udpSocketBoot; } /** * 开始监听和发起入网及认证请求 * * @param request 认证请求信息 * @param callBack 结果回调 */ public void startAuthenticateRequest(AuthenticateRequest request, HDLLinkCallBack callBack) { HDLLinkConfig.getInstance().clearConfig(); //1.启动Socket 开启监听 getUdpBoot(); //2.构建监听Listener // authEvent = //3.监听网关广播的入网指令 EventDispatcher.getInstance().register(TopicConstant.GATEWAY_AUTH_BROADCAST, new EventListener() { @Override public void onMessage(Object msg) { NetworkAccessBroadcastResponse bean = getNetworkAccessBroadcastResponse(msg); if (bean != null) { //移除监听 EventDispatcher.getInstance().remove(TopicConstant.GATEWAY_AUTH_BROADCAST); LogUtils.i("网关入网广播IP: " + bean.getIPAddress()); String ipStr = bean.getIPAddress(); if (!TextUtils.isEmpty(ipStr)) { sendAuthenticateRequest(ipStr, request, callBack); } } } }); } /** * 结束监听入网及认证广播 */ public void endAuthenticateRequest() { //移除监听 EventDispatcher.getInstance().remove(TopicConstant.GATEWAY_AUTH_BROADCAST); } /** * 发送入网及认证请求 * * @param ip 网关IP * @param request 认证请求信息 * @param callBack 结果回调 */ public void sendAuthenticateRequest(String ip, AuthenticateRequest request, HDLLinkCallBack callBack) { if (request == null) { callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_DATA_NULL_ERROR)); } String topic = DEIVCE_AUTH_REQUEST; Gson gs = new Gson(); String requestStr = gs.toJson(request); LinkRequest message = new LinkRequest(topic, requestStr); HdlSocketHelper.sendUdp(getUdpBoot(), ip, UDP_PORT, message, new HdlSocketHelper.HdlSocketListener() { @Override public void onSucceed(Object msg) { if (callBack == null) return; try { AuthenticateResponse bean = getAuthenticateResponseBean(msg); if (bean != null) { if (bean.getCode().equals("200")) { String localSecret = ""; String gatewayId = ""; String ipAddress = ""; if (bean.getAuth() != null) { localSecret = bean.getAuth().getLocalSecret(); } if (bean.getObjects() != null) { gatewayId = bean.getObjects().getGatewayID(); ipAddress = bean.getObjects().getIPAddress(); } //判断网关是否已经注册到云端 if (TextUtils.isEmpty(localSecret) || TextUtils.isEmpty(gatewayId)) { //认证失败,网关未注册到云端 callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_AUTH_ERROR_GATEWAY_NOT_REGISTERED)); } else { HDLLinkConfig.getInstance().saveConfig(localSecret, gatewayId, ipAddress); callBack.onSuccess("认证成功"); } } else if (bean.getCode().equals("14013")){ //认证失败,该MAC对应的设备密钥不存在 callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_AUTH_MAC_KEY_ERROR_)); } else{ //认证失败,错误码: LogUtils.e("认证失败,错误码:" + bean.getCode()); callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_AUTH_ERROR)); } } else { callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_DATA_ERROR)); } } catch (Exception e) { callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_DATA_ERROR)); } } @Override public void onFailure() { LogUtils.i(TAG, "onFailure: "); if (callBack == null) return; callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_TIMEOUT_ERROR)); } }); } // /** // * 发送入网及认证请求 // * // * @param callBack 结果回调 // */ // public void sendAuthenticateRequest(CallBack callBack) { // String macStr = "AA000000000000BB"; // String secret = "87ae414b7a853f65"; // String mac_key = stringToMD5(stringToMD5(macStr + secret)); // // String versionString = "HDL_V1.0.1"; // String time = String.valueOf(System.currentTimeMillis()); // // //1.设置认证信息 // AuthenticateRequest.RequestBean requestBean = new AuthenticateRequest.RequestBean(); // requestBean.setMAC(macStr); // requestBean.setSupplier("HDL"); // requestBean.setFirmwareVersion(versionString); // requestBean.setHardwareModel("1956F"); // AuthenticateRequest.AuthBean authbean = new AuthenticateRequest.AuthBean(); // authbean.setSpk("ir.module"); // authbean.setMACKey(mac_key); // authbean.setRequest(requestBean); // // // //2.设置设备信息 // AuthenticateDeviceInfoBean infoBean = new AuthenticateDeviceInfoBean(); // infoBean.setDeviceMAC(macStr); // infoBean.setIPMAC(macStr); // infoBean.setDeviceName("HDL面板"); // infoBean.setAccessMode("HDL"); // infoBean.setOID(getOid()); // infoBean.setSid(getSid()); //// infoBean.set // AuthenticateRequest.VersionBean[] versionBeans = new AuthenticateRequest.VersionBean[]{new AuthenticateRequest.VersionBean("FW", versionString), new AuthenticateRequest.VersionBean("HW", "1956F")}; // infoBean.setVersions(versionBeans); // AuthenticateRequest request = new AuthenticateRequest(IdUtils.getUUId(), time, infoBean, authbean); // // String ip = IpUtils.getBroadcastAddress(); // ip = "192.168.10.102"; // sendAuthenticateRequest(ip, request, callBack); // } public interface SearchGatewayCallBack extends BaseCallBack { /** * 搜索网关成功 * * @param gatewaySearchBean */ void onSuccess(GatewaySearchBean gatewaySearchBean); } /** * 开始搜索所有网关,有网关回复就回调,上层自己做去重判断 * * @param callBack 回调 */ public void startSearchAllGateway(SearchGatewayCallBack callBack) { } /** * 暂停搜索网关 */ public void endSearchAllGateway() { } /** * 组播搜索指定网关是否在线,搜索到则返回指定的网关对象 * * @param callBack 回调 */ public void searchGatewayMulticast(SearchGatewayCallBack callBack) { searchGateway(HDLLinkConfig.getInstance().getGatewayId(), UDP_GROUP_IP, UDP_PORT, callBack); } /** * 组播搜索指定网关是否在线,搜索到则返回指定的网关对象 * * @param callBack 回调 */ public void searchGatewayBroadcast(SearchGatewayCallBack callBack) { if (!HDLLinkConfig.getInstance().checkIfCertified()) { if (callBack != null) { callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_UNAUTHORIZED_ERROR)); } return; } String ip = IpUtils.getBroadcastAddress(); searchGateway(HDLLinkConfig.getInstance().getGatewayId(), ip, UDP_PORT, callBack); } /** * 设备控制 */ public void propertyDown(List request, HDLLinkCallBack callBack) { String time = String.valueOf(System.currentTimeMillis()); final BaseLocalResponse> data = new BaseLocalResponse<>(); data.setId(IdUtils.getUUId()); data.setTime_stamp(time); data.setObjects(request); String topic = HDLLinkConfig.getInstance().getFullTopic(TopicConstant.PROPERTY_DOWN); LinkRequest message = new LinkRequest(topic, GsonConvert.getGson().toJson(data)); String ip = IpUtils.getBroadcastAddress(); HdlSocketHelper.sendUdp(getUdpBoot(), ip, UDP_PORT, message, new HdlSocketHelper.HdlSocketListener() { @Override public void onSucceed(Object msg) { if (callBack == null) return; callBack.onSuccess("控制成功"); } @Override public void onFailure() { if (callBack == null) return; callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_CONTROL_FAILURE_ERROR)); } }); } /** * 通用发送指令 * 1秒没响应就让他重新发送,重试3次 * * @param topic 发送数据 * @param bodyStr 回复的主题 * @param broadcast 是否要广播 * @param callBack 回调 */ public void udpSendMsg(String topic, String bodyStr,boolean broadcast, HDLLinkResponseCallBack callBack) { if (TextUtils.isEmpty(topic) || TextUtils.isEmpty(bodyStr)) { if (callBack != null) { callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_DATA_NULL_ERROR)); } return; } if (!HDLLinkConfig.getInstance().checkIfCertified()) { if (callBack != null) { callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_UNAUTHORIZED_ERROR)); } return; } LinkRequest message = new LinkRequest(topic, bodyStr); String ip = HDLLinkConfig.getInstance().getIpAddress(); if(broadcast) { ip = IpUtils.getBroadcastAddress(); } HdlSocketHelper.sendUdp(getUdpBoot(), ip, UDP_PORT, message, new HdlSocketHelper.HdlSocketListener() { @Override public void onSucceed(Object msg) { if (callBack == null) return; callBack.onSuccess((LinkResponse) msg); } @Override public void onFailure() { if (callBack == null) return; callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_TIMEOUT_ERROR)); } } ); } /** * 通用发送指令 只发一次,不监听回复,不重发 * * @param topic 发送数据 * @param bodyStr 回复的主题 * @param broadcast 是否广播 */ public void udpSendMsg(String topic, String bodyStr,boolean broadcast) { if (TextUtils.isEmpty(topic) || TextUtils.isEmpty(bodyStr)) { LogUtils.e( "参数不能为空,不能发送UDP数据"); return; } if (!HDLLinkConfig.getInstance().checkIfCertified()) { LogUtils.e("未认证,请先认证再调用UDP发送方法"); return; } LinkRequest message = new LinkRequest(topic, bodyStr); String ip = HDLLinkConfig.getInstance().getIpAddress(); if(broadcast) { ip = IpUtils.getBroadcastAddress(); } HdlSocketHelper.sendUdpOne(getUdpBoot(), ip, UDP_PORT, message); } private GatewaySearchBean getGatewaySearchBean(Object msg) { GatewaySearchBean searchBean = null; if (msg instanceof LinkResponse) { LinkResponse linkResponse = (LinkResponse) msg; String data = linkResponse.getData(); if (!TextUtils.isEmpty(data)) { final BaseLocalResponse response = GsonConvert.getGson().fromJson(data, new TypeToken>() { }.getType()); searchBean = response.getObjects(); } } return searchBean; } private AuthenticateResponse getAuthenticateResponseBean(Object msg) { AuthenticateResponse mBean = null; if (msg instanceof LinkResponse) { LinkResponse linkResponse = (LinkResponse) msg; String data = linkResponse.getData(); if (!TextUtils.isEmpty(data)) { AuthenticateResponse response = GsonConvert.getGson().fromJson(data, new TypeToken() { }.getType()); mBean = response; } } return mBean; } private NetworkAccessBroadcastResponse getNetworkAccessBroadcastResponse(Object msg) { NetworkAccessBroadcastResponse mBean = null; if (msg instanceof LinkResponse) { LinkResponse linkResponse = (LinkResponse) msg; String data = linkResponse.getData(); if (!TextUtils.isEmpty(data)) { NetworkAccessBroadcastResponse response = GsonConvert.getGson().fromJson(data, new TypeToken() { }.getType()); mBean = response; } } return mBean; } /** * 网关搜索相关 */ private static final int MAX_SEARCH_COUNT = 10;//总共搜索测试 private final AtomicInteger searchGatewayCount = new AtomicInteger(0); ; private final AtomicBoolean isSearchGatewaySuccess = new AtomicBoolean(true); private String searchGatewayId = ""; private SearchGatewayCallBack mSearchGatewayCallBack; private void initSearchGatewayEvent() { LogUtils.i("搜索网关", "initSearchGatewayEvent"); searchGatewayEvent = new EventListener() { @Override public void onMessage(Object msg) { try { if (msg instanceof LinkResponse) { LinkResponse linkResponse = (LinkResponse) msg; String data = linkResponse.getData(); if (!TextUtils.isEmpty(data)) { final BaseLocalResponse response = GsonConvert.getGson().fromJson(data, new TypeToken>() { }.getType()); GatewaySearchBean searchBean = response.getObjects(); if (searchBean != null && !TextUtils.isEmpty(searchBean.getGatewayId())) { searchBean.setIp_address(linkResponse.getSource_ipAddress()); if (searchBean.getGatewayId().contains(searchGatewayId)&&!TextUtils.isEmpty(searchGatewayId)) { removeSearchGatewayEvent();//移除搜索网关监听 isSearchGatewaySuccess.set(true);//搜索成功标记 searchGatewayCount.set(11);//次数标记 HDLLinkConfig.getInstance().setCurrentGateway(searchBean);//设置当前网关 if (mSearchGatewayCallBack != null) { mSearchGatewayCallBack.onSuccess(searchBean); } } } } } } catch (Exception e) { } } }; } private void initListenerGatewayEvent() { LogUtils.i("初始化永久监听网关广播事件,不用移除此事件"); EventListener gatewayEvent = new EventListener() { @Override public void onMessage(Object msg) { try { if (msg instanceof LinkResponse) { LinkResponse linkResponse = (LinkResponse) msg; String data = linkResponse.getData(); LogUtils.i("接收到网关信息:" + data); if (!TextUtils.isEmpty(data)) { final BaseLocalResponse response = GsonConvert.getGson().fromJson(data, new TypeToken>() { }.getType()); GatewaySearchBean gateway = response.getObjects(); if (gateway != null && !TextUtils.isEmpty(gateway.getGatewayId())) { //可能网关带过来的ip不对 gateway.setIp_address(linkResponse.getSource_ipAddress()); //主网关并且是当前绑定的网关 if ("true".equals(gateway.getMaster().toLowerCase()) && gateway.getGatewayId().equals(HDLLinkConfig.getInstance().getGatewayId())) { HDLLinkConfig.getInstance().setCurrentGateway(gateway);//设置当前网关 if(!TextUtils.isEmpty( gateway.getIp_address())) { HDLLinkConfig.getInstance().setIpAddress(gateway.getIp_address()); } //更新当前网关的信息 HDLLinkConfig.getInstance().reSaveConfig(); } } } } } catch (Exception e) { } } }; EventDispatcher.getInstance().registerIo(TopicConstant.GATEWAY_SEARCH_REPLY, gatewayEvent); } /** * 搜索指定网关是否在线,搜索到则返回指定的网关对象 * * @param gatewayId 网关id * @param ipAddress 目标的IP地址 * @param port 目标的端口 * @param callBack 回调 */ public void searchGateway(String gatewayId, String ipAddress, int port, SearchGatewayCallBack callBack) { this.searchGatewayId = gatewayId; this.mSearchGatewayCallBack = callBack; //重置参数 searchGatewayCount.set(0); isSearchGatewaySuccess.set(false); String time = String.valueOf(System.currentTimeMillis()); JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("id", IdUtils.getUUId()); jsonObject.addProperty("time_stamp", time); LinkRequest message = new LinkRequest(TopicConstant.GATEWAY_SEARCH, jsonObject.toString()); //注册搜索网关监听 registerSearchGatewayEvent(); new Thread(new Runnable() { @Override public void run() { while (searchGatewayCount.get() < 10 && (!isSearchGatewaySuccess.get())) { try { //搜索网关 searchGatewayCount.set(searchGatewayCount.get() + 1); LogUtils.i("搜索网关", "搜索网关第" + searchGatewayCount.get() + "次"); getUdpBoot().sendMsg(ipAddress, port, message.getSendBytes()); Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); } } if (!isSearchGatewaySuccess.get()) { try { LogUtils.e("搜索网关", "搜索10次,指定网关都没回复,回调超时"); //搜索10次,指定网关都没回复,回调超时 callBackSearchGatewayTimeout(); }catch (Exception e){} } } }).start(); } /** * 注册搜索网关监听 */ private void registerSearchGatewayEvent() { LogUtils.i("搜索网关", "注册搜索网关监听"); EventDispatcher.getInstance().registerIo(TopicConstant.GATEWAY_SEARCH_REPLY, searchGatewayEvent); } /** * 移除搜索网关监听 */ private void removeSearchGatewayEvent() { LogUtils.i("搜索网关", "移除搜索网关监听"); EventDispatcher.getInstance().remove(TopicConstant.GATEWAY_SEARCH_REPLY, searchGatewayEvent); } /** * 回调搜索网关超时 */ private void callBackSearchGatewayTimeout() { removeSearchGatewayEvent(); ThreadToolUtils.getInstance().runOnUiThread(new Runnable() { @Override public void run() { if (mSearchGatewayCallBack != null) { mSearchGatewayCallBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_SEARCH_GATEWAY_TIMEOUT_ERROR)); } } }); } /** * 搜索在线所有的网关,包括当前住宅的及没有绑定过其它住宅的网关 * * @param ipAddress 目标的IP地址 * @param port 目标的端口 * @param callBack 回调 */ public void searchGateway(String ipAddress, int port, SearchGatewayCallBack callBack) { // this.searchGatewayId = gatewayId; // this.mSearchGatewayCallBack = callBack; // //重置参数 // searchGatewayCount.set(0); // isSearchGatewaySuccess.set(false); String time = String.valueOf(System.currentTimeMillis()); JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("id", IdUtils.getUUId()); jsonObject.addProperty("time_stamp", time); LinkRequest message = new LinkRequest(TopicConstant.GATEWAY_SEARCH, jsonObject.toString()); //注册搜索网关监听 registerSearchGatewayEvent(); new Thread(new Runnable() { @Override public void run() { while (searchGatewayCount.get() < 10 && (!isSearchGatewaySuccess.get())) { try { //搜索网关 searchGatewayCount.set(searchGatewayCount.get() + 1); LogUtils.i("搜索网关", "搜索网关第" + searchGatewayCount.get() + "次"); getUdpBoot().sendMsg(ipAddress, port, message.getSendBytes()); Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); } } if (!isSearchGatewaySuccess.get()) { //搜索10次,指定网关都没回复,回调超时 callBackSearchGatewayTimeout(); LogUtils.e("搜索网关", "搜索10次,指定网关都没回复,回调超时"); } } }).start(); } }