panlinlin
2021-01-15 503f891c9e443551309a91b38493ac49413dbe35
完成向上级联->点播--增加了sdp解析
修复修改平台主键带来的bug
15个文件已修改
6个文件已添加
1057 ■■■■■ 已修改文件
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatformCatch.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/Codec.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/MediaDescription.java 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/RFC4566_28181.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/SdpLine.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/SdpParser.java 230 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/SessionDescription.java 162 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java 260 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/RegisterResponseProcessor.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/PatformChannelMapper.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/platform/PlatformController.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
@@ -28,6 +28,8 @@
    public static final String PLATFORM_REGISTER_PREFIX = "VMP_platform_register_";
    public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_platform_register_info_";
    public static final String Pattern_Topic = "VMP_keeplive_platform_";
    public static final String EVENT_ONLINE_REGISTER = "1";
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
@@ -45,11 +45,11 @@
            ParentPlatformCatch parentPlatformCatch = new ParentPlatformCatch();
            parentPlatformCatch.setParentPlatform(parentPlatform);
            parentPlatformCatch.setId(parentPlatform.getDeviceGBId());
            parentPlatformCatch.setId(parentPlatform.getServerGBId());
            redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
            // 发送平台未注册消息
            publisher.platformNotRegisterEventPublish(parentPlatform.getDeviceGBId());
            publisher.platformNotRegisterEventPublish(parentPlatform.getServerGBId());
        }
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatformCatch.java
@@ -10,6 +10,8 @@
    // 注册未回复次数
    private int registerAliveReply;
    private String callId;
    private ParentPlatform parentPlatform;
    public String getId() {
@@ -43,4 +45,12 @@
    public void setParentPlatform(ParentPlatform parentPlatform) {
        this.parentPlatform = parentPlatform;
    }
    public String getCallId() {
        return callId;
    }
    public void setCallId(String callId) {
        this.callId = callId;
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/Codec.java
New file
@@ -0,0 +1,65 @@
/*
    This file is part of Peers, a java SIP softphone.
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    Copyright 2010 Yohann Martineau
*/
package com.genersoft.iot.vmp.gb28181.sdp;
public class Codec {
    private int payloadType;
    private String name;
    public int getPayloadType() {
        return payloadType;
    }
    public void setPayloadType(int payloadType) {
        this.payloadType = payloadType;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Codec)) {
            return false;
        }
        Codec codec = (Codec)obj;
        if (codec.getName() == null) {
            return name == null;
        }
        return codec.getName().equalsIgnoreCase(name);
    }
    @Override
    public String toString() {
        StringBuffer buf = new StringBuffer();
        buf.append(RFC4566_28181.TYPE_ATTRIBUTE).append(RFC4566_28181.SEPARATOR);
        buf.append(RFC4566_28181.ATTR_RTPMAP).append(RFC4566_28181.ATTR_SEPARATOR);
        buf.append(payloadType).append(" ").append(name).append("/");
        buf.append(9000).append("\r\n");
        return buf.toString();
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/MediaDescription.java
New file
@@ -0,0 +1,123 @@
/*
    This file is part of Peers, a java SIP softphone.
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    Copyright 2007, 2008, 2009, 2010 Yohann Martineau
 */
package com.genersoft.iot.vmp.gb28181.sdp;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.Hashtable;
import java.util.List;
public class MediaDescription {
    private String type;
    private InetAddress ipAddress;
    // attributes not codec-related
    private Hashtable<String, String> attributes;
    private int port;
    private List<Codec> codecs;
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public Hashtable<String, String> getAttributes() {
        return attributes;
    }
    public void setAttributes(Hashtable<String, String> attributes) {
        this.attributes = attributes;
    }
    public InetAddress getIpAddress() {
        return ipAddress;
    }
    public void setIpAddress(InetAddress ipAddress) {
        this.ipAddress = ipAddress;
    }
    public int getPort() {
        return port;
    }
    public void setPort(int port) {
        this.port = port;
    }
    public List<Codec> getCodecs() {
        return codecs;
    }
    public void setCodecs(List<Codec> codecs) {
        this.codecs = codecs;
    }
    @Override
    public String toString() {
        StringBuffer buf = new StringBuffer();
        buf.append(RFC4566_28181.TYPE_MEDIA).append(RFC4566_28181.SEPARATOR);
        buf.append(type).append(" ").append(port);
        buf.append(" RTP/AVP");
        if (codecs != null) {
            for (Codec codec: codecs) {
                buf.append(" ");
                buf.append(codec.getPayloadType());
            }
            buf.append("\r\n");
        }
        if (ipAddress != null) {
            int ipVersion;
            if (ipAddress instanceof Inet4Address) {
                ipVersion = 4;
            } else if (ipAddress instanceof Inet6Address) {
                ipVersion = 6;
            } else {
                throw new RuntimeException("unknown ip version: " + ipAddress);
            }
            buf.append(RFC4566_28181.TYPE_CONNECTION).append(RFC4566_28181.SEPARATOR);
            buf.append("IN IP").append(ipVersion).append(" ");
            buf.append(ipAddress.getHostAddress()).append("\r\n");
        }
        if (codecs != null) {
            for (Codec codec: codecs) {
                buf.append(codec.toString());
            }
        }
        if (attributes != null) {
            for (String attributeName: attributes.keySet()) {
                buf.append(RFC4566_28181.TYPE_ATTRIBUTE).append(RFC4566_28181.SEPARATOR);
                buf.append(attributeName);
                String attributeValue = attributes.get(attributeName);
                if (attributeValue != null && !"".equals(attributeValue.trim())) {
                    buf.append(":").append(attributeValue);
                }
                buf.append("\r\n");
            }
        }
        return buf.toString();
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/RFC4566_28181.java
New file
@@ -0,0 +1,51 @@
/*
    This file is part of Peers, a java SIP softphone.
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    Copyright 2007, 2008, 2009, 2010 Yohann Martineau
*/
package com.genersoft.iot.vmp.gb28181.sdp;
public class RFC4566_28181 {
    public static final char VERSION = '0';
    public static final char TYPE_VERSION    = 'v';
    public static final char TYPE_ORIGIN     = 'o';
    public static final char TYPE_SUBJECT    = 's';
    public static final char TYPE_INFO       = 'i';
    public static final char TYPE_URI        = 'u';
    public static final char TYPE_EMAIL      = 'e';
    public static final char TYPE_PHONE      = 'p';
    public static final char TYPE_CONNECTION = 'c';
    public static final char TYPE_BANDWITH   = 'b';
    public static final char TYPE_TIME       = 't';
    public static final char TYPE_REPEAT     = 'r';
    public static final char TYPE_ZONE       = 'z';
    public static final char TYPE_KEY        = 'k';
    public static final char TYPE_ATTRIBUTE  = 'a';
    public static final char TYPE_MEDIA      = 'm';
    public static final char TYPE_SSRC       = 'y';
    public static final char TYPE_MEDIA_DES  = 'f';
    public static final char SEPARATOR       = '=';
    public static final char ATTR_SEPARATOR  = ':';
    public static final String MEDIA_AUDIO   = "audio";
    public static final String ATTR_RTPMAP   = "rtpmap";
    public static final String ATTR_SENDRECV = "sendrecv";
}
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/SdpLine.java
New file
@@ -0,0 +1,38 @@
/*
    This file is part of Peers, a java SIP softphone.
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    Copyright 2007, 2008, 2009, 2010 Yohann Martineau
*/
package com.genersoft.iot.vmp.gb28181.sdp;
public class SdpLine {
    private char type;
    private String value;
    public char getType() {
        return type;
    }
    public void setType(char type) {
        this.type = type;
    }
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/SdpParser.java
New file
@@ -0,0 +1,230 @@
/*
    This file is part of Peers, a java SIP softphone.
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    Copyright 2007, 2008, 2009, 2010 Yohann Martineau
*/
package com.genersoft.iot.vmp.gb28181.sdp;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
public class SdpParser {
    public SessionDescription parse(byte[] body) throws IOException {
        if (body == null || body.length == 0) {
            return null;
        }
        ByteArrayInputStream in = new ByteArrayInputStream(body);
        InputStreamReader inputStreamReader = new InputStreamReader(in);
        BufferedReader reader = new BufferedReader(inputStreamReader);
        SessionDescription sessionDescription = new SessionDescription();
        //version
        String line = reader.readLine();
        if (line.length() < 3) {
            return null;
        }
        if (line.charAt(0) != RFC4566_28181.TYPE_VERSION
                || line.charAt(1) != RFC4566_28181.SEPARATOR
                || line.charAt(2) != RFC4566_28181.VERSION) {
            return null;
        }
        //origin
        line = reader.readLine();
        if (line.length() < 3) {
            return null;
        }
        if (line.charAt(0) != RFC4566_28181.TYPE_ORIGIN
                || line.charAt(1) != RFC4566_28181.SEPARATOR) {
            return null;
        }
        line = line.substring(2);
        String[] originArr = line.split(" ");
        if (originArr == null || originArr.length != 6) {
            return null;
        }
        sessionDescription.setUsername(originArr[0]);
        sessionDescription.setId(Long.parseLong(originArr[1]));
        sessionDescription.setVersion(Long.parseLong(originArr[2]));
        sessionDescription.setIpAddress(InetAddress.getByName(originArr[5]));
        //name
        line = reader.readLine();
        if (line.length() < 3) {
            return null;
        }
        if (line.charAt(0) != RFC4566_28181.TYPE_SUBJECT
                || line.charAt(1) != RFC4566_28181.SEPARATOR) {
            return null;
        }
        sessionDescription.setName(line.substring(2));
        //session connection and attributes
        Hashtable<String, String> sessionAttributes = new Hashtable<String, String>();
        sessionDescription.setAttributes(sessionAttributes);
        while ((line = reader.readLine()) != null
                && line.charAt(0) != RFC4566_28181.TYPE_MEDIA) {
            if (line.length() > 3
                    && line.charAt(0) == RFC4566_28181.TYPE_CONNECTION
                    && line.charAt(1) == RFC4566_28181.SEPARATOR) {
                String connection = parseConnection(line.substring(2));
                if (connection == null) {
                    continue;
                }
                sessionDescription.setIpAddress(InetAddress.getByName(connection));
            } else if (line.length() > 3
                    && line.charAt(0) == RFC4566_28181.TYPE_ATTRIBUTE
                    && line.charAt(1) == RFC4566_28181.SEPARATOR) {
                String value = line.substring(2);
                int pos = value.indexOf(RFC4566_28181.ATTR_SEPARATOR);
                if (pos > -1) {
                    sessionAttributes.put(value.substring(0, pos),
                            value.substring(pos + 1));
                } else {
                    sessionAttributes.put(value, "");
                }
            }
        }
        if (line == null) {
            return null;
        }
        //we are at the first media line
        ArrayList<SdpLine> mediaLines = new ArrayList<SdpLine>();
        do {
            if (line.length() < 2) {
                return null;
            }
            if (line.charAt(1) != RFC4566_28181.SEPARATOR) {
                return null;
            }
            if (line.charAt(0) == RFC4566_28181.TYPE_SSRC) {
                sessionDescription.setSsrc(line.length() >=2 ?line.substring(2):"");
            }else if (line.charAt(0) == RFC4566_28181.TYPE_MEDIA_DES) {
                sessionDescription.setGbMediaDescriptions(line.length() >=2 ?line.substring(2):"");
            }else {
                SdpLine mediaLine = new SdpLine();
                mediaLine.setType(line.charAt(0));
                mediaLine.setValue(line.substring(2));
                mediaLines.add(mediaLine);
            }
        }
        while ((line = reader.readLine()) != null );
        ArrayList<MediaDescription> mediaDescriptions = new ArrayList<MediaDescription>();
        sessionDescription.setMediaDescriptions(mediaDescriptions);
        for (SdpLine sdpLine : mediaLines) {
            MediaDescription mediaDescription;
            if (sdpLine.getType() == RFC4566_28181.TYPE_MEDIA) {
                String[] mediaArr = sdpLine.getValue().split(" ");
                if (mediaArr == null || mediaArr.length < 4) {
                    return null;
                }
                mediaDescription = new MediaDescription();
                mediaDescription.setType(mediaArr[0]);
                //TODO manage port range
                mediaDescription.setPort(Integer.parseInt(mediaArr[1]));
                mediaDescription.setAttributes(new Hashtable<String, String>());
                List<Codec> codecs = new ArrayList<Codec>();
                for (int i = 3; i < mediaArr.length; ++i) {
                    int payloadType = Integer.parseInt(mediaArr[i]);
                    Codec codec = new Codec();
                    codec.setPayloadType(payloadType);
                    codec.setName("unsupported");
                    codecs.add(codec);
                }
                mediaDescription.setCodecs(codecs);
                mediaDescriptions.add(mediaDescription);
            } else {
                mediaDescription = mediaDescriptions.get(mediaDescriptions.size() - 1);
                String sdpLineValue = sdpLine.getValue();
                if (sdpLine.getType() == RFC4566_28181.TYPE_CONNECTION) {
                    String ipAddress = parseConnection(sdpLineValue);
                    mediaDescription.setIpAddress(InetAddress.getByName(ipAddress));
                } else if (sdpLine.getType() == RFC4566_28181.TYPE_ATTRIBUTE) {
                    Hashtable<String, String> attributes = mediaDescription.getAttributes();
                    int pos = sdpLineValue.indexOf(RFC4566_28181.ATTR_SEPARATOR);
                    if (pos > -1) {
                        String name = sdpLineValue.substring(0, pos);
                        String value = sdpLineValue.substring(pos + 1);
                        pos = value.indexOf(" ");
                        if (pos > -1) {
                            int payloadType;
                            try {
                                payloadType = Integer.parseInt(value.substring(0, pos));
                                List<Codec> codecs = mediaDescription.getCodecs();
                                for (Codec codec: codecs) {
                                    if (codec.getPayloadType() == payloadType) {
                                        value = value.substring(pos + 1);
                                        pos = value.indexOf("/");
                                        if (pos > -1) {
                                            value = value.substring(0, pos);
                                            codec.setName(value);
                                        }
                                        break;
                                    }
                                }
                            } catch (NumberFormatException e) {
                                attributes.put(name, value);
                            }
                        } else {
                            attributes.put(name, value);
                        }
                    } else {
                        attributes.put(sdpLineValue, "");
                    }
                }
            }
        }
        sessionDescription.setMediaDescriptions(mediaDescriptions);
        for (MediaDescription description : mediaDescriptions) {
            if (description.getIpAddress() == null) {
                InetAddress sessionAddress = sessionDescription.getIpAddress();
                if (sessionAddress == null) {
                    return null;
                }
                description.setIpAddress(sessionAddress);
            }
        }
        return sessionDescription;
    }
    private String parseConnection(String line) {
        String[] connectionArr = line.split(" ");
        if (connectionArr == null || connectionArr.length != 3) {
            return null;
        }
        return connectionArr[2];
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/sdp/SessionDescription.java
New file
@@ -0,0 +1,162 @@
/*
    This file is part of Peers, a java SIP softphone.
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    Copyright 2007, 2008, 2009, 2010 Yohann Martineau
*/
package com.genersoft.iot.vmp.gb28181.sdp;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.Hashtable;
import java.util.List;
public class SessionDescription {
    private long id;
    private long version;
    private String name;
    private String username;
    private InetAddress ipAddress;
    private List<MediaDescription> mediaDescriptions;
    private Hashtable<String, String> attributes;
    private String ssrc;
    private String gbMediaDescriptions;
    public SessionDescription() {
    }
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public InetAddress getIpAddress() {
        return ipAddress;
    }
    public void setIpAddress(InetAddress ipAddress) {
        this.ipAddress = ipAddress;
    }
    public List<MediaDescription> getMediaDescriptions() {
        return mediaDescriptions;
    }
    public void setMediaDescriptions(List<MediaDescription> mediaDescriptions) {
        this.mediaDescriptions = mediaDescriptions;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public long getVersion() {
        return version;
    }
    public void setVersion(long version) {
        this.version = version;
    }
    public Hashtable<String, String> getAttributes() {
        return attributes;
    }
    public void setAttributes(Hashtable<String, String> attributes) {
        this.attributes = attributes;
    }
    public String getSsrc() {
        return ssrc;
    }
    public void setSsrc(String ssrc) {
        this.ssrc = ssrc;
    }
    public String getGbMediaDescriptions() {
        return gbMediaDescriptions;
    }
    public void setGbMediaDescriptions(String gbMediaDescriptions) {
        this.gbMediaDescriptions = gbMediaDescriptions;
    }
    @Override
    public String toString() {
        StringBuilder buf = new StringBuilder();
        buf.append("v=0\r\n");
        buf.append("o=").append(username).append(" ").append(id);
        buf.append(" ").append(version);
        int ipVersion;
        if (ipAddress instanceof Inet4Address) {
            ipVersion = 4;
        } else if (ipAddress instanceof Inet6Address) {
            ipVersion = 6;
        } else {
            throw new RuntimeException("unknown ip version: " + ipAddress);
        }
        buf.append(" IN IP").append(ipVersion).append(" ");
        String hostAddress = ipAddress.getHostAddress();
        buf.append(hostAddress).append("\r\n");
        buf.append("s=").append(name).append("\r\n");
        buf.append("c=IN IP").append(ipVersion).append(" ");
        buf.append(hostAddress).append("\r\n");
        buf.append("t=0 0\r\n");
        if (attributes != null){
            for (String attributeName: attributes.keySet()) {
                String attributeValue = attributes.get(attributeName);
                buf.append("a=").append(attributeName);
                if (attributeValue != null && !"".equals(attributeValue.trim())) {
                    buf.append(":");
                    buf.append(attributeValue);
                    buf.append("\r\n");
                }
            }
        }
        if (mediaDescriptions != null){
            for (MediaDescription mediaDescription: mediaDescriptions) {
                buf.append(mediaDescription.toString());
            }
        }
        if (ssrc != null){
            buf.append("y=").append(ssrc).append("\r\n");
        }
        if (gbMediaDescriptions != null){
            buf.append("f=").append(gbMediaDescriptions).append("\r\n");
        }
        return buf.toString();
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
@@ -119,6 +119,9 @@
            processor.setRequestEvent(evt);
            processor.setTcpSipProvider(getTcpSipProvider());
            processor.setUdpSipProvider(getUdpSipProvider());
            processor.setCmderFroPlatform(cmderFroPlatform);
            processor.setStorager(storager);
            return processor;
        } else if (Request.REGISTER.equals(method)) {
            RegisterRequestProcessor processor = new RegisterRequestProcessor();
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -70,7 +70,7 @@
    @Override
    public boolean unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) {
        parentPlatform.setExpires("0");
        ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getDeviceGBId());
        ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId());
        if (parentPlatformCatch != null) {
            parentPlatformCatch.setParentPlatform(parentPlatform);
            redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
@@ -86,11 +86,21 @@
            if (www == null ) {
                request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform, 1L, null, null);
                // 将 callid 写入缓存, 等注册成功可以更新状态
                CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
                redisCatchStorage.updatePlatformRegisterInfo(callIdHeader.getCallId(), parentPlatform.getServerGBId());
                sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (event)->{
                    redisCatchStorage.delPlatformRegisterInfo(callIdHeader.getCallId());
                    if (errorEvent != null) {
                        errorEvent.response(event);
                    }
                });
            }else {
                request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform, null, null, callId, www);
            }
            transmitRequest(parentPlatform, request, errorEvent, okEvent);
            transmitRequest(parentPlatform, request, null, okEvent);
            return true;
        } catch (ParseException e) {
            e.printStackTrace();
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
@@ -1,71 +1,231 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.address.SipURI;
import javax.sip.header.ContentTypeHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.SubjectHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.sdp.Codec;
import com.genersoft.iot.vmp.gb28181.sdp.MediaDescription;
import com.genersoft.iot.vmp.gb28181.sdp.SdpParser;
import com.genersoft.iot.vmp.gb28181.sdp.SessionDescription;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import gov.nist.javax.sip.address.AddressImpl;
import gov.nist.javax.sip.address.SipUri;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.text.ParseException;
import java.util.List;
/**    
 * @Description:处理INVITE请求
 * @author: swwheihei
 * @date:   2020年5月3日 下午4:43:52
 * @author: panll
 * @date:   2021年1月14日
 */
public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
    private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class);
    private SIPCommanderFroPlatform cmderFroPlatform;
    private IVideoManagerStorager storager;
    /**
     * 处理invite请求
     * 
     * @param request
     * @param evt
     *            请求消息
     */ 
    @Override
    public void process(RequestEvent evt) {
        // TODO 优先级99 Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令
//        Request request = requestEvent.getRequest();
//
//        try {
//            // 发送100 Trying
//            ServerTransaction serverTransaction = getServerTransaction(requestEvent);
//            // 查询目标地址
//            URI reqUri = request.getRequestURI();
//            URI contactURI = currUser.get(reqUri);
//
//            System.out.println("processInvite rqStr=" + reqUri + " contact=" + contactURI);
//
//            // 根据Request uri来路由,后续的响应消息通过VIA来路由
//            Request cliReq = messageFactory.createRequest(request.toString());
//            cliReq.setRequestURI(contactURI);
//
//            HeaderFactory headerFactory = SipFactory.getInstance().createHeaderFactory();
//            Via callerVia = (Via) request.getHeader(Via.NAME);
//            Via via = (Via) headerFactory.createViaHeader(SIPMain.ip, SIPMain.port, "UDP",
//                    callerVia.getBranch() + "sipphone");
//
//            cliReq.removeHeader(Via.NAME);
//            cliReq.addHeader(via);
//
//            // 更新contact的地址
//            ContactHeader contactHeader = headerFactory.createContactHeader();
//            Address address = SipFactory.getInstance().createAddressFactory()
//                    .createAddress("sip:sipsoft@" + SIPMain.ip + ":" + SIPMain.port);
//            contactHeader.setAddress(address);
//            contactHeader.setExpires(3600);
//            cliReq.setHeader(contactHeader);
//
//            clientTransactionId = sipProvider.getNewClientTransaction(cliReq);
//            clientTransactionId.sendRequest();
//
//            System.out.println("processInvite clientTransactionId=" + clientTransactionId.toString());
//
//            System.out.println("send invite to callee: " + cliReq);
//        } catch (TransactionUnavailableException e1) {
//            e1.printStackTrace();
//        } catch (SipException e) {
//            e.printStackTrace();
//        } catch (ParseException e) {
//            e.printStackTrace();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        //  Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令
        try {
            Request request = evt.getRequest();
            SipURI sipURI = (SipURI) request.getRequestURI();
            String channelId = sipURI.getUser();
            String platformId = null;
//            SubjectHeader subjectHeader = (SubjectHeader)request.getHeader(SubjectHeader.NAME);
//            // 查询通道是否存在 不存在回复404
//            if (subjectHeader != null) { // 存在则从subjectHeader 获取平台信息
//                String subject = subjectHeader.getSubject();
//                if (subject != null) {
//                    String[] info1 = subject.split(",");
//                    if (info1 != null && info1 .length == 2) {
//                        String[] info2 = info1[1].split(":");
//                        if (info2 != null && info2.length == 2) {
//                            platformId = info2[0];
//                        }
//                    }
//                }
//            }
            FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
            AddressImpl address = (AddressImpl) fromHeader.getAddress();
            SipUri uri = (SipUri) address.getURI();
            platformId = uri.getUser();
//            if (platformId == null) { // 不存在则从fromHeader 获取平台信息
//                FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
//                platformId = fromHeader.getName();
//            }
            if (platformId == null || channelId == null) {
                response400Ack(evt); // 参数不全, 发400,请求错误
                return;
            }
            // 查询平台下是否有该通道
            DeviceChannel channel = storager.queryChannelInParentPlatform(platformId, channelId);
            if (channel == null) {
                response404Ack(evt); // 通道不存在,发404,资源不存在
                return;
            }else {
                response100Ack(evt); // 通道存在,发100,trying
            }
            // 解析sdp消息
            byte[] sdpByteArray = request.getRawContent();
            SdpParser sdpParser = new SdpParser(); // TODO keng
            SessionDescription sdp = sdpParser.parse(sdpByteArray);
            //  获取支持的格式
            List<MediaDescription> mediaDescriptions = sdp.getMediaDescriptions();
            // 查看是否支持PS 负载96
            String ip = null;
            int port = -1;
            for (MediaDescription mediaDescription : mediaDescriptions) {
                List<Codec> codecs = mediaDescription.getCodecs();
                for (Codec codec : codecs) {
                    if("96".equals(codec.getPayloadType()) || "PS".equals(codec.getName()) || "ps".equals(codec.getName())) {
                        ip = mediaDescription.getIpAddress().getHostName();
                        port = mediaDescription.getPort();
                        break;
                    }
                }
            }
            if (ip == null || port == -1) { // TODO 没有合适的视频流格式, 可配置是否使用第一个media信息
                if (mediaDescriptions.size() > 0) {
                    ip = mediaDescriptions.get(0).getIpAddress().getHostName();
                    port = mediaDescriptions.get(0).getPort();
                }
            }
            if (ip == null || port == -1) {
                response488Ack(evt);
                return;
            }
            String ssrc = sdp.getSsrc();
            // 通知下级推流,
            // 查找合适的端口推流,
            // 发送 200ok
            // 收到ack后调用推流接口
        } catch (SipException | InvalidArgumentException | ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            logger.warn("sdp解析错误");
            e.printStackTrace();
        }
    }
    /***
     * 回复100 trying
     * @param evt
     * @throws SipException
     * @throws InvalidArgumentException
     * @throws ParseException
     */
    private void response100Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException {
        Response response = getMessageFactory().createResponse(Response.TRYING, evt.getRequest());
        getServerTransaction(evt).sendResponse(response);
    }
    /***
     * 回复404
     * @param evt
     * @throws SipException
     * @throws InvalidArgumentException
     * @throws ParseException
     */
    private void response404Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException {
        Response response = getMessageFactory().createResponse(Response.NOT_FOUND, evt.getRequest());
        getServerTransaction(evt).sendResponse(response);
    }
    /***
     * 回复400
     * @param evt
     * @throws SipException
     * @throws InvalidArgumentException
     * @throws ParseException
     */
    private void response400Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException {
        Response response = getMessageFactory().createResponse(Response.BAD_REQUEST, evt.getRequest());
        getServerTransaction(evt).sendResponse(response);
    }
    /***
     * 回复488
     * @param evt
     * @throws SipException
     * @throws InvalidArgumentException
     * @throws ParseException
     */
    private void response488Ack(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException {
        Response response = getMessageFactory().createResponse(Response.NOT_ACCEPTABLE_HERE, evt.getRequest());
        getServerTransaction(evt).sendResponse(response);
    }
    /***
     * 回复200 OK
     * @param evt
     * @throws SipException
     * @throws InvalidArgumentException
     * @throws ParseException
     */
    private void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException {
        Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
        ContentTypeHeader contentTypeHeader = getHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
        response.setContent(sdp, contentTypeHeader);
        getServerTransaction(evt).sendResponse(response);
    }
    public SIPCommanderFroPlatform getCmderFroPlatform() {
        return cmderFroPlatform;
    }
    public void setCmderFroPlatform(SIPCommanderFroPlatform cmderFroPlatform) {
        this.cmderFroPlatform = cmderFroPlatform;
    }
    public IVideoManagerStorager getStorager() {
        return storager;
    }
    public void setStorager(IVideoManagerStorager storager) {
        this.storager = storager;
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
@@ -15,6 +15,8 @@
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce;
import gov.nist.javax.sip.address.AddressImpl;
import gov.nist.javax.sip.address.SipUri;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
@@ -166,10 +168,15 @@
            Element deviceIdElement = rootElement.element("DeviceID");
            String deviceId = deviceIdElement.getText();
            Element deviceListElement = rootElement.element("DeviceList");
            FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
            AddressImpl address = (AddressImpl) fromHeader.getAddress();
            SipUri uri = (SipUri) address.getURI();
            String platformId = uri.getUser();
            // if (deviceListElement == null) { // 存在DeviceList则为响应 catalog, 不存在DeviceList则为查询请求
            if (name == "Query") { // 区分是Response——查询响应,还是Query——查询请求
                    // TODO 后续将代码拆分
                ParentPlatform parentPlatform = storager.queryParentPlatById(deviceId);
                ParentPlatform parentPlatform = storager.queryParentPlatById(platformId);
                if (parentPlatform == null) {
                    response404Ack(evt);
                    return;
@@ -179,9 +186,8 @@
                    Element snElement = rootElement.element("SN");
                    String sn = snElement.getText();
                    FromHeader fromHeader = (FromHeader)evt.getRequest().getHeader(FromHeader.NAME);
                    // 准备回复通道信息
                    List<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getDeviceGBId());
                    List<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
                    if (channelReduces.size() >0 ) {
                        for (ChannelReduce channelReduce : channelReduces) {
                            DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
@@ -499,7 +505,7 @@
    }
    /***
     * 回复200 OK
     * 回复404
     * @param evt
     * @throws SipException
     * @throws InvalidArgumentException
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/RegisterResponseProcessor.java
@@ -61,10 +61,14 @@
    public void process(ResponseEvent evt, SipLayer layer, SipConfig config) {
        // TODO Auto-generated method stub
        Response response = evt.getResponse();
        ToHeader toHeader = (ToHeader) response.getHeader(ToHeader.NAME);
        SipUri uri = (SipUri)toHeader.getAddress().getURI();
        String platformGBId = uri.getAuthority().getUser();
        CallIdHeader callIdHeader = (CallIdHeader) response.getHeader(CallIdHeader.NAME);
        String callId = callIdHeader.getCallId();
        String platformGBId = redisCatchStorage.queryPlatformRegisterInfo(callId);
        if (platformGBId == null) {
            logger.info(String.format("未找到callId: %s 的注册/注销平台id", callId ));
            return;
        }
        logger.info(String.format("收到 %s 的注册/注销%S响应", platformGBId, response.getStatusCode() ));
        ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(platformGBId);
@@ -80,18 +84,13 @@
        if (response.getStatusCode() == 401) {
            WWWAuthenticateHeader www = (WWWAuthenticateHeader)response.getHeader(WWWAuthenticateHeader.NAME);
            CallIdHeader callIdHeader = (CallIdHeader)response.getHeader(CallIdHeader.NAME);
            String callId = callIdHeader.getCallId();
            sipCommanderForPlatform.register(parentPlatform, callId, www, null, null);
        }else if (response.getStatusCode() == 200){
            // 注册成功
            logger.info(String.format("%s 注册成功", platformGBId ));
            redisCatchStorage.delPlatformRegisterInfo(callId);
            parentPlatform.setStatus(true);
            storager.updateParentPlatform(parentPlatform);
            //
            redisCatchStorage.updatePlatformRegister(parentPlatform);
            redisCatchStorage.updatePlatformKeepalive(parentPlatform);
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
@@ -73,4 +73,9 @@
    void delPlatformRegister(String platformGbId);
    void updatePlatformRegisterInfo(String callId, String platformGbId);
    String queryPlatformRegisterInfo(String callId);
    void delPlatformRegisterInfo(String callId);
}
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
@@ -233,4 +233,5 @@
    int delChannelForGB(String platformId, List<ChannelReduce> channelReduces);
    DeviceChannel queryChannelInParentPlatform(String platformId, String channelId);
}
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
@@ -24,7 +24,7 @@
    @Update("UPDATE parent_platform " +
            "SET enable=#{enable}, " +
            "name=#{name}," +
            "serverGBId=#{serverGBId}," +
            "deviceGBId=#{deviceGBId}," +
            "serverGBDomain=#{serverGBDomain}, " +
            "serverIP=#{serverIP}," +
            "serverPort=#{serverPort}, " +
@@ -39,13 +39,13 @@
            "PTZEnable=#{PTZEnable}, " +
            "rtcp=#{rtcp}, " +
            "status=#{status} " +
            "WHERE deviceGBId=#{deviceGBId}")
            "WHERE serverGBId=#{serverGBId}")
    int updateParentPlatform(ParentPlatform parentPlatform);
    @Delete("DELETE FROM parent_platform WHERE deviceGBId=#{deviceGBId}")
    @Delete("DELETE FROM parent_platform WHERE serverGBId=#{serverGBId}")
    int delParentPlatform(ParentPlatform parentPlatform);
    @Select("SELECT *,( SELECT count(0) FROM platform_gb_channel pc WHERE pc.platformId = pp.deviceGBId) as channelCount FROM parent_platform pp ")
    @Select("SELECT *,( SELECT count(0) FROM platform_gb_channel pc WHERE pc.platformId = pp.serverGBId) as channelCount FROM parent_platform pp ")
    List<ParentPlatform> getParentPlatformList();
    @Select("SELECT * FROM parent_platform WHERE enable=#{enable}")
src/main/java/com/genersoft/iot/vmp/storager/dao/PatformChannelMapper.java
@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.storager.dao;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
@@ -39,4 +40,9 @@
            "DELETE FROM platform_gb_channel WHERE platformId='${platformId}'"  +
            "</script>")
    int cleanChannelForGB(String platformId);
    @Select("SELECT * FROM device_channel WHERE deviceId = (SELECT deviceId FROM platform_gb_channel WHERE " +
            "platformId='${platformId}' AND channelId='${channelId}' ) AND channelId='${channelId}'")
    DeviceChannel queryChannelInParentPlatform(String platformId, String channelId);
}
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -169,13 +169,13 @@
    @Override
    public void updatePlatformKeepalive(ParentPlatform parentPlatform) {
        String key = VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX + parentPlatform.getDeviceGBId();
        String key = VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX + parentPlatform.getServerGBId();
        redis.set(key, "", Integer.parseInt(parentPlatform.getKeepTimeout()));
    }
    @Override
    public void updatePlatformRegister(ParentPlatform parentPlatform) {
        String key = VideoManagerConstants.PLATFORM_REGISTER_PREFIX + parentPlatform.getDeviceGBId();
        String key = VideoManagerConstants.PLATFORM_REGISTER_PREFIX + parentPlatform.getServerGBId();
        redis.set(key, "", Integer.parseInt(parentPlatform.getExpires()));
    }
@@ -198,4 +198,22 @@
    public void delPlatformRegister(String platformGbId) {
        redis.del(VideoManagerConstants.PLATFORM_REGISTER_PREFIX + platformGbId);
    }
    @Override
    public void updatePlatformRegisterInfo(String callId, String platformGbId) {
        String key = VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + callId;
        redis.set(key, platformGbId);
    }
    @Override
    public String queryPlatformRegisterInfo(String callId) {
        return (String)redis.get(VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + callId);
    }
    @Override
    public void delPlatformRegisterInfo(String callId) {
        redis.del(VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + callId);
    }
}
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
@@ -254,7 +254,7 @@
    public boolean deleteParentPlatform(ParentPlatform parentPlatform) {
        int result = platformMapper.delParentPlatform(parentPlatform);
        // 删除关联的通道
        patformChannelMapper.cleanChannelForGB(parentPlatform.getDeviceGBId());
        patformChannelMapper.cleanChannelForGB(parentPlatform.getServerGBId());
        return result > 0;
    }
@@ -329,4 +329,10 @@
        return result;
    }
    @Override
    public DeviceChannel queryChannelInParentPlatform(String platformId, String channelId) {
        DeviceChannel channel = patformChannelMapper.queryChannelInParentPlatform(platformId, channelId);
        return channel;
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/platform/PlatformController.java
@@ -110,7 +110,7 @@
        if (logger.isDebugEnabled()) {
            logger.debug("查询所有上级设备API调用");
        }
        if (StringUtils.isEmpty(parentPlatform.getDeviceGBId())
        if (StringUtils.isEmpty(parentPlatform.getServerGBId())
        ){
            return new ResponseEntity<>("missing parameters", HttpStatus.BAD_REQUEST);
        }
@@ -118,14 +118,14 @@
        // 发送离线消息,无论是否成功都删除缓存
        commanderForPlatform.unregister(parentPlatform, (event -> {
            // 清空redis缓存
            redisCatchStorage.delPlatformCatchInfo(parentPlatform.getDeviceGBId());
            redisCatchStorage.delPlatformKeepalive(parentPlatform.getDeviceGBId());
            redisCatchStorage.delPlatformRegister(parentPlatform.getDeviceGBId());
            redisCatchStorage.delPlatformCatchInfo(parentPlatform.getServerGBId());
            redisCatchStorage.delPlatformKeepalive(parentPlatform.getServerGBId());
            redisCatchStorage.delPlatformRegister(parentPlatform.getServerGBId());
        }), (event -> {
            // 清空redis缓存
            redisCatchStorage.delPlatformCatchInfo(parentPlatform.getDeviceGBId());
            redisCatchStorage.delPlatformKeepalive(parentPlatform.getDeviceGBId());
            redisCatchStorage.delPlatformRegister(parentPlatform.getDeviceGBId());
            redisCatchStorage.delPlatformCatchInfo(parentPlatform.getServerGBId());
            redisCatchStorage.delPlatformKeepalive(parentPlatform.getServerGBId());
            redisCatchStorage.delPlatformRegister(parentPlatform.getServerGBId());
        }));
        boolean deleteResult = storager.deleteParentPlatform(parentPlatform);