diff --git a/README.md b/README.md index c23715ef7..5afd26d43 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git # 功能特性 - [X] 集成web界面 - [X] 兼容性良好 +- [X] 跨平台服务,一次编译多端部署, 可以同时用于x86和arm架构 - [X] 接入设备 - [X] 视频预览 - [X] 支持主码流子码流切换 diff --git a/bin/wvp.sh b/bin/wvp.sh new file mode 100644 index 000000000..d4d1c8515 --- /dev/null +++ b/bin/wvp.sh @@ -0,0 +1,115 @@ +#!/bin/bash + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +function log() { + message="[Polaris Log]: $1 " + case "$1" in + *"Fail"* | *"Error"* | *"请使用 root 或 sudo 权限运行此脚本"*) + echo -e "${RED}${message}${NC}" 2>&1 | tee -a + ;; + *"Success"*) + echo -e "${GREEN}${message}${NC}" 2>&1 | tee -a + ;; + *"Ignore"* | *"Jump"*) + echo -e "${YELLOW}${message}${NC}" 2>&1 | tee -a + ;; + *) + echo -e "${BLUE}${message}${NC}" 2>&1 | tee -a + ;; + esac +} +echo +cat < /dev/tcp/127.0.0.1/3306" ] + interval: 15s + timeout: 5s + retries: 10 + start_period: 10s + networks: + - media-net + environment: + MYSQL_DATABASE: wvp + MYSQL_ROOT_PASSWORD: root + MYSQL_USER: root + MYSQL_PASSWORD: root + TZ: Asia/Shanghai + ports: + - 3306:3306 + volumes: + - ./mysql/conf:/etc/mysql/conf.d + - ./logs/mysql:/logs + - ./volumes/mysql/data:/var/lib/mysql + command: [ + 'mysqld', + '--default-authentication-plugin=mysql_native_password', + '--innodb-buffer-pool-size=80M', + '--character-set-server=utf8mb4', + '--collation-server=utf8mb4_general_ci', + '--default-time-zone=+8:00', + '--lower-case-table-names=1' + ] + + polaris-media: + image: polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-media:latest + restart: always + networks: + - media-net + ports: + - "10935:10935" + - "5540:5540" + - "6080:6080" + volumes: + - ./volumes/video:/opt/media/www/record/ + - ./logs/media:/opt/media/log/ + + polaris-wvp: + image: polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-wvp:latest + restart: always + networks: + - media-net + ports: + - "18978:18978" + - "8116:8116/udp" + - "8116:8116/tcp" depends_on: - - redis + - polaris-redis + - polaris-mysql + - polaris-media + links: + - polaris-redis + - polaris-mysql + - polaris-media + volumes: + - ./wvp/wvp/:/opt/wvp/wvp/ + - ./logs/wvp:/opt/wvp/logs/ + environment: + TZ: "Asia/Shanghai" + # 本机的IP + SIP_HOST: 127.0.0.1 + STREAM_HOST: 127.0.0.1 + ZLM_HOST: polaris-media + ZLM_PORT: 6080 + ZLM_SERCERT: su6TiedN2rVAmBbIDX0aa0QTiBJLBdcf + REDIS_HOST: polaris-redis + REDIS_PORT: 6379 + DATABASE_HOST: polaris-mysql + DATABASE_PORT: 3306 + DATABASE_USER: wvp + DATABASE_PASSWORD: wvp + # 前端跨域配置,nginx容器所在物理机IP + NGINX_HOST: http://127.0.0.1:8080 + + polaris-nginx: + image: polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-nginx:latest + ports: + - "8080:8080" + depends_on: + - polaris-wvp + links: + - polaris-wvp + environment: + WVP_HOST: polaris-wvp + WVP_PORT: 18978 + volumes: + - ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf + - ./logs/nginx:/var/log/nginx + networks: + - media-net + +networks: + media-net: + driver: bridge \ No newline at end of file diff --git a/docker/docker-upgrade.sh b/docker/docker-upgrade.sh new file mode 100755 index 000000000..9c2d75f9b --- /dev/null +++ b/docker/docker-upgrade.sh @@ -0,0 +1,5 @@ +#/bin/bash +set -e + +docker compose down +docker compose up -d --remove-orphans \ No newline at end of file diff --git a/docker/media/Dockerfile b/docker/media/Dockerfile new file mode 100644 index 000000000..a7b6c165d --- /dev/null +++ b/docker/media/Dockerfile @@ -0,0 +1,91 @@ +FROM ubuntu:20.04 AS build + +#shell,rtmp,rtsp,rtsps,http,rtp +EXPOSE 10935/tcp +EXPOSE 5540/tcp +EXPOSE 6080/tcp +EXPOSE 10000/udp +EXPOSE 10000/tcp +EXPOSE 8000/udp +EXPOSE 8000/tcp +EXPOSE 9000/udp + +# ADD sources.list /etc/apt/sources.list + +RUN apt-get update && \ + DEBIAN_FRONTEND="noninteractive" \ + apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + git \ + curl \ + vim \ + wget \ + ca-certificates \ + tzdata \ + libssl-dev \ + gcc \ + g++ \ + gdb && \ + apt-get autoremove -y && \ + apt-get clean -y && \ + rm -rf /var/lib/apt/lists/* + +RUN mkdir -p /opt/media +WORKDIR /opt/media +RUN git clone --depth 1 https://gitee.com/xia-chu/ZLMediaKit && \ + cd ZLMediaKit && git submodule update --init + +# 3rdpart init +WORKDIR /opt/media/ZLMediaKit/3rdpart +RUN wget https://polaris-tian-generic.pkg.coding.net/qt/dependencies/openssl-1.1.1k.tar.gz?version=latest -O openssl-1.1.1k.tar.gz && \ + tar -xvzf openssl-1.1.1k.tar.gz && \ + cd openssl-1.1.1k && ./config shared --openssldir=/usr/local/openssl --prefix=/usr/local/openssl && \ + make && make install && \ + echo "/usr/local/lib64/" >> /etc/ld.so.conf && \ + echo "/usr/local/openssl/lib" >> /etc/ld.so.conf && \ + ldconfig && \ + ln -s /usr/local/openssl/bin/openssl /usr/local/bin/openssl + +WORKDIR /opt/media/ZLMediaKit/3rdpart +RUN wget https://github.com/cisco/libsrtp/archive/v2.3.0.tar.gz -O libsrtp-2.3.0.tar.gz && \ + tar xfv libsrtp-2.3.0.tar.gz && \ + mv libsrtp-2.3.0 libsrtp && \ + cd libsrtp && ./configure --enable-openssl --with-openssl-dir=/usr/local/openssl && make -j $(nproc) && make install + + +WORKDIR /opt/media/ZLMediaKit/build +RUN cmake .. -DENABLE_WEBRTC=true -DOPENSSL_ROOT_DIR=/usr/local/openssl -DOPENSSL_LIBRARIES=/usr/local/openssl/lib && \ + cmake --build . --target MediaServer +COPY config.ini /opt/media/ZLMediaKit/release/linux/Debug/ + +FROM ubuntu:20.04 + +RUN apt-get update && \ + DEBIAN_FRONTEND="noninteractive" \ + apt-get install -y --no-install-recommends \ + vim \ + wget \ + ca-certificates \ + tzdata \ + curl \ + libssl-dev \ + ffmpeg \ + gcc \ + g++ \ + gdb && \ + apt-get autoremove -y && \ + apt-get clean -y && \ + rm -rf /var/lib/apt/lists/* + +ENV TZ=Asia/Shanghai +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \ + && echo $TZ > /etc/timezone && \ + mkdir -p /opt/media/bin/www + +WORKDIR /opt/media/bin/ +COPY --from=build /opt/media/ZLMediaKit/release/linux/Debug/MediaServer /opt/media/ZLMediaKit/default.pem /opt/media/bin/ +COPY --from=build /opt/media/ZLMediaKit/release/linux/Debug/config.ini /opt/media/conf/ +COPY --from=build /opt/media/ZLMediaKit/www/ /opt/media/bin/www/ +ENV PATH /opt/media/bin:$PATH +CMD ["./MediaServer","-s", "default.pem", "-c", "../conf/config.ini", "-l","0"] \ No newline at end of file diff --git a/docker/media/build.sh b/docker/media/build.sh new file mode 100755 index 000000000..edcc16c8d --- /dev/null +++ b/docker/media/build.sh @@ -0,0 +1,8 @@ +#/bin/bash +set -e + +version=2.7.3 + +docker build -t polaris-media:${version} . +docker tag polaris-media:${version} polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-media:${version} +docker tag polaris-media:${version} polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-media:latest \ No newline at end of file diff --git a/docker/media/config.ini b/docker/media/config.ini new file mode 100644 index 000000000..2098e8d49 --- /dev/null +++ b/docker/media/config.ini @@ -0,0 +1,196 @@ +; auto-generated by mINI class { + +[api] +apiDebug=1 +defaultSnap=./www/logo.png +downloadRoot=./www; +secret=su6TiedN2rVAmBbIDX0aa0QTiBJLBdcf +snapRoot=./www/snap/ + +[cluster] +origin_url= +retry_count=3 +timeout_sec=15 + +[ffmpeg] +bin=/usr/bin/ffmpeg +cmd=%s -re -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s +log=./ffmpeg/ffmpeg.log +restart_sec=0 +snap=%s -rtsp_transport tcp -i %s -y -f mjpeg -frames:v 1 %s + +[general] +broadcast_player_count_changed=0 +check_nvidia_dev=1 +enableVhost=0 +enable_ffmpeg_log=0 +flowThreshold=1024 +listen_ip=:: +maxStreamWaitMS=15000 +mediaServerId=polaris +mergeWriteMS=0 +resetWhenRePlay=1 +streamNoneReaderDelayMS=20000 +unready_frame_cache=100 +wait_add_track_ms=3000 +wait_audio_track_data_ms=1000 +wait_track_ready_ms=10000 + +[hls] +broadcastRecordTs=0 +deleteDelaySec=10 +fastRegister=0 +fileBufSize=65536 +segDelay=0 +segDur=2 +segKeep=0 +segNum=3 +segRetain=5 + +[hook] +alive_interval=10.0 +enable=1 +on_flow_report= +on_http_access= +on_play= +on_publish= +on_record_mp4= +on_record_ts= +on_rtp_server_timeout= +on_rtsp_auth= +on_rtsp_realm= +on_send_rtp_stopped= +on_server_exited= +on_server_keepalive= +on_server_started= +on_shell_login= +on_stream_changed= +on_stream_none_reader= +on_stream_not_found= +retry=1 +retry_delay=3.0 +stream_changed_schemas=rtsp/rtmp/fmp4/ts/hls/hls.fmp4 +timeoutSec=30 + +[http] +allow_cross_domains=1 +allow_ip_range= +charSet=utf-8 +dirMenu=1 +forbidCacheSuffix= +forwarded_ip_header= +keepAliveSecond=30 +maxReqSize=40960 +notFound=404 Not Found

您访问的资源不存在!


ZLMediaKit(git hash:8ccb4e9/%aI,branch:master,build time:2024-11-07T10:34:19)
+port=6080 +rootPath=./www +sendBufSize=65536 +sslport=4443 +virtualPath= + +[multicast] +addrMax=239.255.255.255 +addrMin=239.0.0.0 +udpTTL=64 + +[protocol] +add_mute_audio=1 +auto_close=0 +continue_push_ms=3000 +enable_audio=1 +enable_fmp4=1 +enable_hls=1 +enable_hls_fmp4=0 +enable_mp4=0 +enable_rtmp=1 +enable_rtsp=1 +enable_ts=1 +fmp4_demand=0 +hls_demand=0 +hls_save_path=./www +modify_stamp=2 +mp4_as_player=0 +mp4_max_second=3600 +mp4_save_path=/home +paced_sender_ms=0 +rtmp_demand=0 +rtsp_demand=0 +ts_demand=0 + +[record] +appName=record +enableFmp4=0 +fastStart=0 +fileBufSize=65536 +fileRepeat=0 +sampleMS=500 + +[rtc] +datachannel_echo=0 +externIP= +maxRtpCacheMS=5000 +maxRtpCacheSize=2048 +max_bitrate=0 +min_bitrate=0 +nackIntervalRatio=1.0 +nackMaxCount=15 +nackMaxMS=3000 +nackMaxSize=2048 +nackRtpSize=8 +port=8000 +preferredCodecA=PCMA,PCMU,opus,mpeg4-generic +preferredCodecV=H264,H265,AV1,VP9,VP8 +rembBitRate=0 +start_bitrate=0 +tcpPort=8000 +timeoutSec=30 + +[rtmp] +directProxy=1 +enhanced=0 +handshakeSecond=15 +keepAliveSecond=15 +port=10935 +sslport=0 + +[rtp] +audioMtuSize=600 +h264_stap_a=1 +lowLatency=0 +rtpMaxSize=10 +videoMtuSize=1400 + +[rtp_proxy] +dumpDir= +gop_cache=1 +h264_pt=98 +h265_pt=99 +opus_pt=100 +port=10000 +port_range=30000-30500 +ps_pt=96 +rtp_g711_dur_ms=100 +timeoutSec=15 +udp_recv_socket_buffer=4194304 + +[rtsp] +authBasic=0 +directProxy=1 +handshakeSecond=15 +keepAliveSecond=15 +lowLatency=0 +port=5540 +rtpTransportType=-1 +sslport=0 + +[shell] +maxReqSize=1024 +port=0 + +[srt] +latencyMul=4 +pktBufSize=8192 +port=9000 +timeoutSec=5 + +; } --- diff --git a/docker/mysql/Dockerfile b/docker/mysql/Dockerfile new file mode 100644 index 000000000..ffdda5213 --- /dev/null +++ b/docker/mysql/Dockerfile @@ -0,0 +1,3 @@ +FROM mysql:8.0.32 + +ADD ./db/*.sql /docker-entrypoint-initdb.d/ \ No newline at end of file diff --git a/docker/mysql/build.sh b/docker/mysql/build.sh new file mode 100755 index 000000000..133ab4430 --- /dev/null +++ b/docker/mysql/build.sh @@ -0,0 +1,8 @@ +#/bin/bash +set -e + +version=2.7.3 + +docker build -t polaris-mysql:${version} . +docker tag polaris-mysql:${version} polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-mysql:${version} +docker tag polaris-mysql:${version} polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-mysql:latest \ No newline at end of file diff --git a/docker/mysql/db/privileges.sql b/docker/mysql/db/privileges.sql new file mode 100644 index 000000000..3aa6ce84b --- /dev/null +++ b/docker/mysql/db/privileges.sql @@ -0,0 +1,3 @@ +use mysql; +grant all privileges on wvp.* to 'ylcx'@'%'; +flush privileges; \ No newline at end of file diff --git a/docker/mysql/db/wvp.sql b/docker/mysql/db/wvp.sql new file mode 100644 index 000000000..d65a05d85 --- /dev/null +++ b/docker/mysql/db/wvp.sql @@ -0,0 +1,769 @@ +/*建库*/ +DROP DATABASE IF EXISTS `wvp`; + +CREATE DATABASE `wvp` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +USE `wvp`; + +/*建表*/ +drop table IF EXISTS wvp_device; +create table IF NOT EXISTS wvp_device +( + id serial primary key, + device_id character varying(50) not null, + name character varying(255), + manufacturer character varying(255), + model character varying(255), + firmware character varying(255), + transport character varying(50), + stream_mode character varying(50), + on_line bool default false, + register_time character varying(50), + keepalive_time character varying(50), + ip character varying(50), + create_time character varying(50), + update_time character varying(50), + port integer, + expires integer, + subscribe_cycle_for_catalog integer DEFAULT 0, + subscribe_cycle_for_mobile_position integer DEFAULT 0, + mobile_position_submission_interval integer DEFAULT 5, + subscribe_cycle_for_alarm integer DEFAULT 0, + host_address character varying(50), + charset character varying(50), + ssrc_check bool default false, + geo_coord_sys character varying(50), + media_server_id character varying(50) default 'auto', + custom_name character varying(255), + sdp_ip character varying(50), + local_ip character varying(50), + password character varying(255), + as_message_channel bool default false, + heart_beat_interval integer, + heart_beat_count integer, + position_capability integer, + broadcast_push_after_ack bool default false, + server_id character varying(50), + constraint uk_device_device unique (device_id) +); + +drop table IF EXISTS wvp_device_alarm; +create table IF NOT EXISTS wvp_device_alarm +( + id serial primary key, + device_id character varying(50) not null, + channel_id character varying(50) not null, + alarm_priority character varying(50), + alarm_method character varying(50), + alarm_time character varying(50), + alarm_description character varying(255), + longitude double precision, + latitude double precision, + alarm_type character varying(50), + create_time character varying(50) not null +); + +drop table IF EXISTS wvp_device_mobile_position; +create table IF NOT EXISTS wvp_device_mobile_position +( + id serial primary key, + device_id character varying(50) not null, + channel_id character varying(50) not null, + device_name character varying(255), + time character varying(50), + longitude double precision, + latitude double precision, + altitude double precision, + speed double precision, + direction double precision, + report_source character varying(50), + create_time character varying(50) +); + +drop table IF EXISTS wvp_device_channel; +create table IF NOT EXISTS wvp_device_channel +( + id serial primary key, + device_id character varying(50), + name character varying(255), + manufacturer character varying(50), + model character varying(50), + owner character varying(50), + civil_code character varying(50), + block character varying(50), + address character varying(50), + parental integer, + parent_id character varying(50), + safety_way integer, + register_way integer, + cert_num character varying(50), + certifiable integer, + err_code integer, + end_time character varying(50), + secrecy integer, + ip_address character varying(50), + port integer, + password character varying(255), + status character varying(50), + longitude double precision, + latitude double precision, + ptz_type integer, + position_type integer, + room_type integer, + use_type integer, + supply_light_type integer, + direction_type integer, + resolution character varying(255), + business_group_id character varying(255), + download_speed character varying(255), + svc_space_support_mod integer, + svc_time_support_mode integer, + create_time character varying(50) not null, + update_time character varying(50) not null, + sub_count integer, + stream_id character varying(255), + has_audio bool default false, + gps_time character varying(50), + stream_identification character varying(50), + channel_type int default 0 not null, + gb_device_id character varying(50), + gb_name character varying(255), + gb_manufacturer character varying(255), + gb_model character varying(255), + gb_owner character varying(255), + gb_civil_code character varying(255), + gb_block character varying(255), + gb_address character varying(255), + gb_parental integer, + gb_parent_id character varying(255), + gb_safety_way integer, + gb_register_way integer, + gb_cert_num character varying(50), + gb_certifiable integer, + gb_err_code integer, + gb_end_time character varying(50), + gb_secrecy integer, + gb_ip_address character varying(50), + gb_port integer, + gb_password character varying(50), + gb_status character varying(50), + gb_longitude double, + gb_latitude double, + gb_business_group_id character varying(50), + gb_ptz_type integer, + gb_position_type integer, + gb_room_type integer, + gb_use_type integer, + gb_supply_light_type integer, + gb_direction_type integer, + gb_resolution character varying(255), + gb_download_speed character varying(255), + gb_svc_space_support_mod integer, + gb_svc_time_support_mode integer, + record_plan_id integer, + data_type integer not null, + data_device_id integer not null, + gps_speed double precision, + gps_altitude double precision, + gps_direction double precision, + index (data_type), + index (data_device_id), + constraint uk_wvp_unique_channel unique (gb_device_id) +); + +drop table IF EXISTS wvp_media_server; +create table IF NOT EXISTS wvp_media_server +( + id character varying(255) primary key, + ip character varying(50), + hook_ip character varying(50), + sdp_ip character varying(50), + stream_ip character varying(50), + http_port integer, + http_ssl_port integer, + rtmp_port integer, + rtmp_ssl_port integer, + rtp_proxy_port integer, + rtsp_port integer, + rtsp_ssl_port integer, + flv_port integer, + flv_ssl_port integer, + ws_flv_port integer, + ws_flv_ssl_port integer, + auto_config bool default false, + secret character varying(50), + type character varying(50) default 'zlm', + rtp_enable bool default false, + rtp_port_range character varying(50), + send_rtp_port_range character varying(50), + record_assist_port integer, + default_server bool default false, + create_time character varying(50), + update_time character varying(50), + hook_alive_interval integer, + record_path character varying(255), + record_day integer default 7, + transcode_suffix character varying(255), + server_id character varying(50), + constraint uk_media_server_unique_ip_http_port unique (ip, http_port, server_id) +); + +drop table IF EXISTS wvp_platform; +create table IF NOT EXISTS wvp_platform +( + id serial primary key, + enable bool default false, + name character varying(255), + server_gb_id character varying(50), + server_gb_domain character varying(50), + server_ip character varying(50), + server_port integer, + device_gb_id character varying(50), + device_ip character varying(50), + device_port character varying(50), + username character varying(255), + password character varying(50), + expires character varying(50), + keep_timeout character varying(50), + transport character varying(50), + civil_code character varying(50), + manufacturer character varying(255), + model character varying(255), + address character varying(255), + character_set character varying(50), + ptz bool default false, + rtcp bool default false, + status bool default false, + catalog_group integer, + register_way integer, + secrecy integer, + create_time character varying(50), + update_time character varying(50), + as_message_channel bool default false, + catalog_with_platform integer default 1, + catalog_with_group integer default 1, + catalog_with_region integer default 1, + auto_push_channel bool default true, + send_stream_ip character varying(50), + server_id character varying(50), + constraint uk_platform_unique_server_gb_id unique (server_gb_id) +); + +drop table IF EXISTS wvp_platform_channel; +create table IF NOT EXISTS wvp_platform_channel +( + id serial primary key, + platform_id integer, + device_channel_id integer, + custom_device_id character varying(50), + custom_name character varying(255), + custom_manufacturer character varying(50), + custom_model character varying(50), + custom_owner character varying(50), + custom_civil_code character varying(50), + custom_block character varying(50), + custom_address character varying(50), + custom_parental integer, + custom_parent_id character varying(50), + custom_safety_way integer, + custom_register_way integer, + custom_cert_num character varying(50), + custom_certifiable integer, + custom_err_code integer, + custom_end_time character varying(50), + custom_secrecy integer, + custom_ip_address character varying(50), + custom_port integer, + custom_password character varying(255), + custom_status character varying(50), + custom_longitude double precision, + custom_latitude double precision, + custom_ptz_type integer, + custom_position_type integer, + custom_room_type integer, + custom_use_type integer, + custom_supply_light_type integer, + custom_direction_type integer, + custom_resolution character varying(255), + custom_business_group_id character varying(255), + custom_download_speed character varying(255), + custom_svc_space_support_mod integer, + custom_svc_time_support_mode integer, + constraint uk_platform_gb_channel_platform_id_catalog_id_device_channel_id unique (platform_id, device_channel_id), + constraint uk_platform_gb_channel_device_id unique (custom_device_id) +); + +drop table IF EXISTS wvp_platform_group; +create table IF NOT EXISTS wvp_platform_group +( + id serial primary key, + platform_id integer, + group_id integer, + constraint uk_wvp_platform_group_platform_id_group_id unique (platform_id, group_id) +); + +drop table IF EXISTS wvp_platform_region; +create table IF NOT EXISTS wvp_platform_region +( + id serial primary key, + platform_id integer, + region_id integer, + constraint uk_wvp_platform_region_platform_id_group_id unique (platform_id, region_id) +); + +drop table IF EXISTS wvp_stream_proxy; +create table IF NOT EXISTS wvp_stream_proxy +( + id serial primary key, + type character varying(50), + app character varying(255), + stream character varying(255), + src_url character varying(255), + timeout integer, + ffmpeg_cmd_key character varying(255), + rtsp_type character varying(50), + media_server_id character varying(50), + enable_audio bool default false, + enable_mp4 bool default false, + pulling bool default false, + enable bool default false, + enable_remove_none_reader bool default false, + create_time character varying(50), + name character varying(255), + update_time character varying(50), + stream_key character varying(255), + server_id character varying(50), + enable_disable_none_reader bool default false, + relates_media_server_id character varying(50), + constraint uk_stream_proxy_app_stream unique (app, stream) +); + +drop table IF EXISTS wvp_stream_push; +create table IF NOT EXISTS wvp_stream_push +( + id serial primary key, + app character varying(255), + stream character varying(255), + create_time character varying(50), + media_server_id character varying(50), + server_id character varying(50), + push_time character varying(50), + status bool default false, + update_time character varying(50), + pushing bool default false, + self bool default false, + start_offline_push bool default true, + constraint uk_stream_push_app_stream unique (app, stream) +); + +drop table IF EXISTS wvp_cloud_record; +create table IF NOT EXISTS wvp_cloud_record +( + id serial primary key, + app character varying(255), + stream character varying(255), + call_id character varying(255), + start_time bigint, + end_time bigint, + media_server_id character varying(50), + server_id character varying(50), + file_name character varying(255), + folder character varying(500), + file_path character varying(500), + collect bool default false, + file_size bigint, + time_len bigint +); + +drop table IF EXISTS wvp_user; +create table IF NOT EXISTS wvp_user +( + id serial primary key, + username character varying(255), + password character varying(255), + role_id integer, + create_time character varying(50), + update_time character varying(50), + push_key character varying(50), + constraint uk_user_username unique (username) +); + +drop table IF EXISTS wvp_user_role; +create table IF NOT EXISTS wvp_user_role +( + id serial primary key, + name character varying(50), + authority character varying(50), + create_time character varying(50), + update_time character varying(50) +); + + +drop table IF EXISTS wvp_user_api_key; +create table IF NOT EXISTS wvp_user_api_key +( + id serial primary key, + user_id bigint, + app character varying(255), + api_key text, + expired_at bigint, + remark character varying(255), + enable bool default true, + create_time character varying(50), + update_time character varying(50) +); + + +/*初始数据*/ +INSERT INTO wvp_user +VALUES (1, 'admin', '21232f297a57a5a743894a0e4a801fc3', 1, '2021-04-13 14:14:57', '2021-04-13 14:14:57', + '3e80d1762a324d5b0ff636e0bd16f1e3'); +INSERT INTO wvp_user_role +VALUES (1, 'admin', '0', '2021-04-13 14:14:57', '2021-04-13 14:14:57'); + +drop table IF EXISTS wvp_common_group; +create table IF NOT EXISTS wvp_common_group +( + id serial primary key, + device_id varchar(50) NOT NULL, + name varchar(255) NOT NULL, + parent_id int, + parent_device_id varchar(50) DEFAULT NULL, + business_group varchar(50) NOT NULL, + create_time varchar(50) NOT NULL, + update_time varchar(50) NOT NULL, + civil_code varchar(50) default null, + constraint uk_common_group_device_platform unique (device_id) +); + +drop table IF EXISTS wvp_common_region; +create table IF NOT EXISTS wvp_common_region +( + id serial primary key, + device_id varchar(50) NOT NULL, + name varchar(255) NOT NULL, + parent_id int, + parent_device_id varchar(50) DEFAULT NULL, + create_time varchar(50) NOT NULL, + update_time varchar(50) NOT NULL, + constraint uk_common_region_device_id unique (device_id) +); + +drop table IF EXISTS wvp_record_plan; +create table IF NOT EXISTS wvp_record_plan +( + id serial primary key, + snap bool default false, + name varchar(255) NOT NULL, + create_time character varying(50), + update_time character varying(50) +); + +drop table IF EXISTS wvp_record_plan_item; +create table IF NOT EXISTS wvp_record_plan_item +( + id serial primary key, + start int, + stop int, + week_day int, + plan_id int, + create_time character varying(50), + update_time character varying(50) +); + +/* +* 20240528 +*/ +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20240528`() +BEGIN + IF NOT EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'transcode_suffix') + THEN + ALTER TABLE wvp_media_server ADD transcode_suffix character varying(255); + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'type') + THEN + alter table wvp_media_server + add type character varying(50) default 'zlm'; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'flv_port') + THEN + alter table wvp_media_server add flv_port integer; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'flv_ssl_port') + THEN + alter table wvp_media_server add flv_ssl_port integer; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'ws_flv_port') + THEN + alter table wvp_media_server add ws_flv_port integer; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'ws_flv_ssl_port') + THEN + alter table wvp_media_server add ws_flv_ssl_port integer; + END IF; +END; // +call wvp_20240528(); +DROP PROCEDURE wvp_20240528; +DELIMITER ; + +create table IF NOT EXISTS wvp_user_api_key ( + id serial primary key , + user_id bigint, + app character varying(255) , + api_key text, + expired_at bigint, + remark character varying(255), + enable bool default true, + create_time character varying(50), + update_time character varying(50) +); + +/* +* 20241222 +*/ +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20241222`() +BEGIN + IF EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and INDEX_NAME = 'uk_wvp_device_channel_unique_device_channel') + THEN + alter table wvp_device_channel drop index uk_wvp_device_channel_unique_device_channel; + END IF; + + IF EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and INDEX_NAME = 'uk_wvp_unique_stream_push_id') + THEN + alter table wvp_device_channel drop index uk_wvp_unique_stream_push_id; + END IF; + + IF EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and INDEX_NAME = 'uk_wvp_unique_stream_proxy_id') + THEN + alter table wvp_device_channel drop index uk_wvp_unique_stream_proxy_id; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'data_type') + THEN + alter table wvp_device_channel add data_type integer not null; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'data_device_id') + THEN + alter table wvp_device_channel add data_device_id integer not null; + END IF; + + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'device_db_id') + THEN + update wvp_device_channel wdc INNER JOIN + (SELECT id, device_db_id from wvp_device_channel where device_db_id is not null ) ct on ct.id = wdc.id + set wdc.data_type = 1, wdc.data_device_id = ct.device_db_id where wdc.device_db_id is not null; + alter table wvp_device_channel drop device_db_id; + END IF; + + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'stream_push_id') + THEN + update wvp_device_channel wdc INNER JOIN + (SELECT id, stream_push_id from wvp_device_channel where stream_push_id is not null ) ct on ct.id = wdc.id + set wdc.data_type = 2, wdc.data_device_id = ct.stream_push_id where wdc.stream_push_id is not null; + alter table wvp_device_channel drop stream_push_id; + END IF; + + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'stream_proxy_id') + THEN + update wvp_device_channel wdc INNER JOIN + (SELECT id, stream_proxy_id from wvp_device_channel where stream_proxy_id is not null ) ct on ct.id = wdc.id + set wdc.data_type = 3, wdc.data_device_id = ct.stream_proxy_id where wdc.stream_proxy_id is not null; + alter table wvp_device_channel drop stream_proxy_id; + END IF; +END; // +call wvp_20241222(); +DROP PROCEDURE wvp_20241222; +DELIMITER ; +/* +* 20241231 +*/ +DELIMITER // +CREATE PROCEDURE `wvp_20241231`() +BEGIN + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_stream_proxy' and column_name = 'relates_media_server_id') + THEN + alter table wvp_stream_proxy add relates_media_server_id character varying(50); + END IF; +END; // +call wvp_20241231(); +DROP PROCEDURE wvp_20241231; +DELIMITER ; +/* +* 20250111 +*/ +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20250111`() +BEGIN + IF EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_cloud_record' and INDEX_NAME = 'uk_stream_push_app_stream_path') + THEN + alter table wvp_cloud_record drop index uk_stream_push_app_stream_path ; + END IF; + + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_cloud_record' and column_name = 'folder') + THEN + alter table wvp_cloud_record modify folder varchar(500) null; + END IF; + + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_cloud_record' and column_name = 'file_path') + THEN + alter table wvp_cloud_record modify file_path varchar(500) null; + END IF; +END; // +call wvp_20250111(); +DROP PROCEDURE wvp_20250111; +DELIMITER ; + +/* +* 20250211 +*/ +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20250211`() +BEGIN + IF EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device' and column_name = 'keepalive_interval_time') + THEN + alter table wvp_device change keepalive_interval_time heart_beat_interval integer after as_message_channel; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device' and column_name = 'heart_beat_count') + THEN + alter table wvp_device add heart_beat_count integer; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device' and column_name = 'position_capability') + THEN + alter table wvp_device add position_capability integer; + END IF; +END; // +call wvp_20250211(); +DROP PROCEDURE wvp_20250211; +DELIMITER ; + +/** + * 20250312 + */ +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20250312`() +BEGIN + DECLARE serverId VARCHAR(32) DEFAULT '你的服务ID'; + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device' and column_name = 'server_id') + THEN + alter table wvp_device add server_id character varying(50); + update wvp_device set server_id = serverId; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'server_id') + THEN + alter table wvp_media_server add server_id character varying(50); + update wvp_media_server set server_id = serverId; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_stream_proxy' and column_name = 'server_id') + THEN + alter table wvp_stream_proxy add server_id character varying(50); + update wvp_stream_proxy set server_id = serverId; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_cloud_record' and column_name = 'server_id') + THEN + alter table wvp_cloud_record add server_id character varying(50); + update wvp_cloud_record set server_id = serverId; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_platform' and column_name = 'server_id') + THEN + alter table wvp_platform add server_id character varying(50); + END IF; +END; // +call wvp_20250312(); +DROP PROCEDURE wvp_20250312; +DELIMITER ; + +/* +* 20250319 +*/ +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20250319`() +BEGIN + IF NOT EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'gps_speed') + THEN + alter table wvp_device_channel add gps_speed double precision; + END IF; + + IF NOT EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'gps_altitude') + THEN + alter table wvp_device_channel add gps_altitude double precision; + END IF; + + IF NOT EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'gps_direction') + THEN + alter table wvp_device_channel add gps_direction double precision; + END IF; +END; // +call wvp_20250319(); +DROP PROCEDURE wvp_20250319; +DELIMITER ; + +/* +* 20250402 +*/ +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20250402`() +BEGIN + IF NOT EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and INDEX_NAME = 'data_type') + THEN + create index data_type on wvp_device_channel (data_type); + END IF; + IF NOT EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and INDEX_NAME = 'data_device_id') + THEN + create index data_device_id on wvp_device_channel (data_device_id); + END IF; + +END; // +call wvp_20250402(); +DROP PROCEDURE wvp_20250402; +DELIMITER ; + + + diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile new file mode 100644 index 000000000..91403f8e7 --- /dev/null +++ b/docker/nginx/Dockerfile @@ -0,0 +1,19 @@ +FROM nginx:alpine + +RUN apk add --no-cache bash + +ARG TZ=Asia/Shanghai +RUN \ + sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \ + apk update && \ + apk add tzdata +RUN ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime && \ + echo '${TZ}' > /etc/timezone + +RUN rm -rf /etc/nginx/conf.d/* +RUN mkdir /opt/dist +COPY ./dist /opt/dist +COPY ./conf/nginx.conf /etc/nginx/conf.d + +CMD ["nginx","-g","daemon off;"] + diff --git a/docker/nginx/build.sh b/docker/nginx/build.sh new file mode 100755 index 000000000..717d54664 --- /dev/null +++ b/docker/nginx/build.sh @@ -0,0 +1,11 @@ +#/bin/bash +set -e + +version=2.7.3 + +rm ./dist/static/js/config.js +cp ./config.js ./dist/static/js/ + +docker build -t polaris-nginx:${version} . +docker tag polaris-nginx:${version} polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-nginx:${version} +docker tag polaris-nginx:${version} polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-nginx:latest \ No newline at end of file diff --git a/docker/nginx/conf/nginx.conf b/docker/nginx/conf/nginx.conf new file mode 100644 index 000000000..ede96ec67 --- /dev/null +++ b/docker/nginx/conf/nginx.conf @@ -0,0 +1,55 @@ +#user nobody; +worker_processes 1; + +#error_log logs/error.log; +#error_log logs/error.log notice; +#error_log logs/error.log info; + +#pid logs/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include mime.types; + default_type application/octet-stream; + + sendfile on; + #tcp_nopush on; + + #keepalive_timeout 0; + keepalive_timeout 65; + + #gzip on; + + server { + listen 8080; + server_name localhost; + + location / { + root /opt/dist; + index index.html index.htm; + } + location /record_proxy/{ + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://polaris-wvp:18978/; + } + location /api/ { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://polaris-wvp:18978; + } + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root html; + } + } +} diff --git a/docker/nginx/config.js b/docker/nginx/config.js new file mode 100644 index 000000000..f63449dcf --- /dev/null +++ b/docker/nginx/config.js @@ -0,0 +1,22 @@ + +window.baseUrl = "http://10.10.1.124:18978" + +// map组件全局参数, 注释此内容可以关闭地图功能 +window.mapParam = { + // 开启/关闭地图功能 + enable: true, + // 坐标系 GCJ-02 WGS-84, + coordinateSystem: "GCJ-02", + // 地图瓦片地址 + tilesUrl: "http://webrd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8", + // 瓦片大小 + tileSize: 256, + // 默认层级 + zoom:10, + // 默认地图中心点 + center:[116.41020, 39.915119], + // 地图最大层级 + maxZoom:18, + // 地图最小层级 + minZoom: 3 +} diff --git a/docker/push.sh b/docker/push.sh new file mode 100755 index 000000000..468a9570c --- /dev/null +++ b/docker/push.sh @@ -0,0 +1,15 @@ +#/bin/bash +set -e + +version=2.7.3 + +docker push polaris-tian-docker.pkg.coding.net/qt/polaris/ylcx-media:latest +docker push polaris-tian-docker.pkg.coding.net/qt/polaris/ylcx-mysql:latest +docker push polaris-tian-docker.pkg.coding.net/qt/polaris/ylcx-redis:latest +docker push polaris-tian-docker.pkg.coding.net/qt/polaris/ylcx-wvp:latest +docker push polaris-tian-docker.pkg.coding.net/qt/polaris/ylcx-nginx:latest +docker push polaris-tian-docker.pkg.coding.net/qt/polaris/ylcx-media:${version} +docker push polaris-tian-docker.pkg.coding.net/qt/polaris/ylcx-mysql:${version} +docker push polaris-tian-docker.pkg.coding.net/qt/polaris/ylcx-redis:${version} +docker push polaris-tian-docker.pkg.coding.net/qt/polaris/ylcx-wvp:${version} +docker push polaris-tian-docker.pkg.coding.net/qt/polaris/ylcx-nginx:${version} \ No newline at end of file diff --git a/docker/redis/Dockerfile b/docker/redis/Dockerfile new file mode 100644 index 000000000..d92f80908 --- /dev/null +++ b/docker/redis/Dockerfile @@ -0,0 +1,5 @@ +FROM redis + +RUN mkdir -p /opt/polaris/redis +WORKDIR /opt/polaris/redis +COPY ./conf/redis.conf /opt/polaris/redis/redis.conf \ No newline at end of file diff --git a/docker/redis/build.sh b/docker/redis/build.sh new file mode 100755 index 000000000..a990f8f5e --- /dev/null +++ b/docker/redis/build.sh @@ -0,0 +1,8 @@ +#/bin/bash +set -e + +version=2.7.3 + +docker build -t polaris-redis:${version} . +docker tag polaris-redis:${version} polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-redis:${version} +docker tag polaris-redis:${version} polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-redis:latest \ No newline at end of file diff --git a/docker/redis/conf/redis.conf b/docker/redis/conf/redis.conf new file mode 100644 index 000000000..a151bd428 --- /dev/null +++ b/docker/redis/conf/redis.conf @@ -0,0 +1,2 @@ +#requirepass root +bind 0.0.0.0 \ No newline at end of file diff --git a/docker/redis/redis.conf b/docker/redis/redis.conf deleted file mode 100644 index c211f137e..000000000 --- a/docker/redis/redis.conf +++ /dev/null @@ -1,2 +0,0 @@ -requirepass root -bind 0.0.0.0 diff --git a/docker/wvp/Dockerfile b/docker/wvp/Dockerfile index 34e3babbd..67286b19f 100644 --- a/docker/wvp/Dockerfile +++ b/docker/wvp/Dockerfile @@ -1,81 +1,64 @@ -FROM ubuntu:20.04 as build +FROM ubuntu:20.04 AS build +ARG Platfrom=amd64 +ARG JDK_NAME -ARG gitUrl="https://gitee.com/pan648540858" -ARG zlmGitUrl="https://gitee.com/xia-chu/ZLMediaKit" +EXPOSE 18978/tcp +EXPOSE 8116/tcp +EXPOSE 8116/udp +EXPOSE 8080/tcp -RUN export DEBIAN_FRONTEND=noninteractive &&\ - apt-get update && \ - apt-get install -y --no-install-recommends openjdk-11-jre git maven nodejs npm build-essential \ - cmake ca-certificates openssl ffmpeg &&\ - mkdir -p /opt/wvp/config /opt/wvp/heapdump /opt/wvp/config /opt/assist/config /opt/assist/heapdump /opt/media/www/record +RUN apt-get update && \ + DEBIAN_FRONTEND="noninteractive" \ + apt-get install -y --no-install-recommends \ + wget \ + cmake \ + maven \ + git \ + ca-certificates \ + tzdata \ + curl \ + libpcre3 \ + libpcre3-dev \ + zlib1g-dev \ + openssl \ + libssl-dev \ + gdb && \ + apt-get autoremove -y && \ + apt-get clean -y && \ + rm -rf /var/lib/apt/lists/* -RUN cd /home && \ - git clone "${gitUrl}/maven.git" && \ - cp maven/settings.xml /usr/share/maven/conf/ +# install jdk1.8 +RUN mkdir -p /opt/download +WORKDIR /opt/download +RUN if [ "$Platfrom" = "arm64" ]; \ + then \ + wget https://polaris-tian-generic.pkg.coding.net/qt/autopliot/jdk-8u411-linux-aarch64.tar.gz?version=latest --no-check-certificate -O jdk-8.tar.gz && \ + tar -zxvf /opt/download/jdk-8.tar.gz -C /usr/local/ --transform 's/jdk1.8.0_411/java/' && \ + rm /opt/download/jdk-8.tar.gz; \ + else \ + wget https://polaris-tian-generic.pkg.coding.net/qt/autopliot/jdk-8u202-linux-x64.tar.gz?version=latest --no-check-certificate -O jdk-8.tar.gz && \ + tar -zxvf /opt/download/jdk-8.tar.gz -C /usr/local/ --transform 's/jdk1.8.0_202/java/' && \ + rm /opt/download/jdk-8.tar.gz; \ + fi -RUN cd /home && \ - git clone "${gitUrl}/wvp-GB28181-pro.git" -RUN cd /home/wvp-GB28181-pro/web_src && \ - npm install && \ - npm run build -RUN cd /home/wvp-GB28181-pro && \ - mvn clean package -Dmaven.test.skip=true && \ - cp /home/wvp-GB28181-pro/target/*.jar /opt/wvp/ && \ - cp /home/wvp-GB28181-pro/src/main/resources/application-docker.yml /opt/wvp/config/application.yml +ENV JAVA_HOME /usr/local/java/ +ENV JRE_HOME ${JAVA_HOME}/jre +ENV CLASSPATH .:${JAVA_HOME}/lib:${JRE_HOME}/lib +ENV PATH ${JAVA_HOME}/bin:$PATH -RUN cd /home && \ - git clone "${gitUrl}/wvp-pro-assist.git" -RUN cd /home/wvp-pro-assist && \ - git reset --hard 58f1a79136a55a7cd1593c95b56ddadcc2225b61 && \ - mvn clean package -Dmaven.test.skip=true && \ - cp /home/wvp-pro-assist/target/*.jar /opt/assist/ && \ - cp /home/wvp-pro-assist/src/main/resources/application-dev.yml /opt/assist/config/application.yml +RUN java -version && javac -version -RUN cd /home && \ - git clone --depth=1 "${zlmGitUrl}" -RUN cd /home/ZLMediaKit && \ - git submodule update --init --recursive && \ - mkdir -p build release/linux/Release/ &&\ - cd build && \ - cmake -DCMAKE_BUILD_TYPE=Release .. && \ - make -j4 && \ - rm -rf ../release/linux/Release/config.ini && \ - cp -r ../release/linux/Release/* /opt/media - -RUN cd /opt/wvp && \ - echo '#!/bin/bash' > run.sh && \ - echo 'echo ${WVP_IP}' >> run.sh && \ - echo 'echo ${WVP_CONFIG}' >> run.sh && \ - echo 'cd /opt/assist' >> run.sh && \ - echo 'nohup java ${ASSIST_JVM_CONFIG} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/assist/heapdump/ -jar *.jar --spring.config.location=/opt/assist/config/application.yml --userSettings.record=/opt/media/www/record/ --media.record-assist-port=18081 ${ASSIST_CONFIG} &' >> run.sh && \ - echo 'nohup /opt/media/MediaServer -d -m 3 &' >> run.sh && \ - echo 'cd /opt/wvp' >> run.sh && \ - echo 'java ${WVP_JVM_CONFIG} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/wvp/heapdump/ -jar *.jar --spring.config.location=/opt/wvp/config/application.yml --media.record-assist-port=18081 ${WVP_CONFIG}' >> run.sh && \ - chmod +x run.sh - -FROM ubuntu:20.04 - -EXPOSE 18080/tcp -EXPOSE 5060/tcp -EXPOSE 5060/udp -EXPOSE 6379/tcp -EXPOSE 18081/tcp -EXPOSE 80/tcp -EXPOSE 1935/tcp -EXPOSE 554/tcp -EXPOSE 554/udp -EXPOSE 30000-30500/tcp -EXPOSE 30000-30500/udp - -ENV LC_ALL zh_CN.UTF-8 - -RUN export DEBIAN_FRONTEND=noninteractive &&\ - apt-get update && \ - apt-get install -y --no-install-recommends openjdk-11-jre ca-certificates ffmpeg language-pack-zh-hans && \ - apt-get autoremove -y && \ - apt-get clean -y && \ - rm -rf /var/lib/apt/lists/*dic - -COPY --from=build /opt /opt +RUN mkdir -p /opt/wvp WORKDIR /opt/wvp -CMD ["sh", "run.sh"] +COPY ./wvp /opt/wvp + +WORKDIR /home +RUN cd /home && \ + git clone https://gitee.com/pan648540858/wvp-GB28181-pro.git + +RUN cd /home/wvp-GB28181-pro && \ + mvn clean package -Dmaven.test.skip=true && \ + cp /home/wvp-GB28181-pro/target/*.jar /opt/wvp/wvp.jar + +WORKDIR /opt/wvp +ENTRYPOINT ["java", "-Xms512m", "-Xmx1024m", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=/opt/ylcx/", "-jar", "wvp.jar", "--spring.config.location=/opt/ylcx/wvp/application.yml"] \ No newline at end of file diff --git a/docker/wvp/build.sh b/docker/wvp/build.sh new file mode 100755 index 000000000..f45df290d --- /dev/null +++ b/docker/wvp/build.sh @@ -0,0 +1,8 @@ +#/bin/bash +set -e + +version=2.7.3 + +docker build -t polaris-wvp:${version} . +docker tag polaris-wvp:${version} polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-wvp:${version} +docker tag polaris-wvp:${version} polaris-tian-docker.pkg.coding.net/qt/polaris/polaris-wvp:latest \ No newline at end of file diff --git a/docker/wvp/wvp/application-base.yml b/docker/wvp/wvp/application-base.yml new file mode 100755 index 000000000..c15c6e57f --- /dev/null +++ b/docker/wvp/wvp/application-base.yml @@ -0,0 +1,105 @@ +spring: + # 设置接口超时时间 + mvc: + async: + request-timeout: 20000 + thymeleaf: + cache: false + # [可选]上传文件大小限制 + servlet: + multipart: + max-file-size: 10MB + max-request-size: 100MB + # REDIS数据库配置 + redis: + # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1 + host: 127.0.0.1 + # [必须修改] 端口号 + port: 6379 + # [可选] 数据库 DB + database: 1 + # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接 + password: + # [可选] 超时时间 + timeout: 30000 + # mysql数据源 + datasource: + dynamic: + type: com.zaxxer.hikari.HikariDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true + username: root + password: root +#[可选] 监听的HTTP端口, 网页和接口调用都是这个端口 +server: + port: 18978 + ssl: + # [可选] 是否开启HTTPS访问 + enabled: false +# 作为28181服务器的配置 +sip: + # [必须修改] 本机的IP + ip: 127.0.0.1 + # [可选] + port: 8116 + # [可选] + domain: 3402000000 + # [可选] + id: 34020000002000000001 + password: + alarm: true + +# 默认服务器配置 +media: + id: polaris + # [必须修改]内网IP + ip: 127.0.0.1 + http-port: 6080 + # [可选] 返回流地址时的ip,置空使用 media.ip + stream-ip: 127.0.0.1 + # [可选] wvp在国标信令中使用的ip,此ip为摄像机可以访问到的ip, 置空使用 media.ip + sdp-ip: 127.0.0.1 + # [可选] Hook IP, 默认使用sip.ip + hook-ip: 127.0.0.1 + # [可选] sslport + http-ssl-port: 4443 + rtp-proxy-port: 10000 + rtmp-port: 10935 + rtmp-ssl-port: 41935 + rtsp-port: 5540 + rtsp-ssl-port: 45540 + # [可选] + secret: su6TiedN2rVAmBbIDX0aa0QTiBJLBdcf + # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 + rtp: + # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输 + enable: false + # [可选] + port-range: 30000,30500 + # [可选] + send-port-range: 50502,50506 + + record-path: /opt/media/record + record-day: 7 + record-assist-port: 0 +user-settings: + auto-apply-play: true + play-timeout: 30000 + wait-track: false + record-push-live: false + record-sip: false + stream-on-demand: true + interface-authentication: false + broadcast-for-platform: TCP-PASSIVE + push-stream-after-ack: true + send-to-platforms-when-id-lost: true + interface-authentication-excludes: + - /api/** + push-authority: false + allowed-origins: + - http://localhost:8080 + - http://127.0.0.1:8080 + - http://0.0.0.0:8080 +logging: + config: classpath:logback-spring.xml + diff --git a/docker/wvp/wvp/application-docker.yml b/docker/wvp/wvp/application-docker.yml new file mode 100644 index 000000000..68c411e7b --- /dev/null +++ b/docker/wvp/wvp/application-docker.yml @@ -0,0 +1,106 @@ +spring: + # 设置接口超时时间 + mvc: + async: + request-timeout: 20000 + thymeleaf: + cache: false + # [可选]上传文件大小限制 + servlet: + multipart: + max-file-size: 10MB + max-request-size: 100MB + # REDIS数据库配置 + redis: + # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1 + host: ${REDIS_HOST:127.0.0.1} + # [必须修改] 端口号 + port: ${REDIS_PORT:6379} + # [可选] 数据库 DB + database: 1 + # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接 + password: + # [可选] 超时时间 + timeout: 30000 + # mysql数据源 + datasource: + type: com.zaxxer.hikari.HikariDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://${DATABASE_HOST:127.0.0.1}:${DATABASE_PORT:3306}/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true + username: ${DATABASE_USER:root} + password: ${DATABASE_PASSWORD:root} + +#[可选] 监听的HTTP端口, 网页和接口调用都是这个端口 +server: + port: 18978 + ssl: + # [可选] 是否开启HTTPS访问 + enabled: false +# 作为28181服务器的配置 +sip: + # [必须修改] 本机的IP + ip: ${SIP_HOST:127.0.0.1} + # [可选] + port: 8116 + # [可选] + domain: 3402000000 + # [可选] + id: 34020000002000000001 + password: + alarm: true + +# 默认服务器配置 +media: + id: polaris + # [必须修改] ZLM 内网IP与端口 + ip: ${ZLM_HOST:127.0.0.1} + http-port: ${ZLM_PORT:6080} + # [可选] 返回流地址时的ip,置空使用 media.ip + stream-ip: ${STREAM_HOST:127.0.0.1} + # [可选] wvp在国标信令中使用的ip,此ip为摄像机可以访问到的ip, 置空使用 media.ip + sdp-ip: ${SIP_HOST:127.0.0.1} + # [可选] Hook IP, 默认使用sip.ip + hook-ip: ${SIP_HOST:127.0.0.1} + # [可选] sslport + http-ssl-port: 4443 + rtp-proxy-port: 10000 + rtmp-port: 10935 + rtmp-ssl-port: 41935 + rtsp-port: 5540 + rtsp-ssl-port: 45540 + # [可选] + secret: ${ZLM_SERCERT} + # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 + rtp: + # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输 + enable: false + # [可选] + port-range: 30000,30500 + # [可选] + send-port-range: 50502,50506 + + record-path: /opt/media/record + record-day: 7 + record-assist-port: 0 +user-settings: + auto-apply-play: true + play-timeout: 30000 + wait-track: false + record-push-live: false + record-sip: false + stream-on-demand: true + interface-authentication: false + broadcast-for-platform: TCP-PASSIVE + push-stream-after-ack: true + send-to-platforms-when-id-lost: true + interface-authentication-excludes: + - /api/** + push-authority: false + allowed-origins: + - http://localhost:8080 + - http://127.0.0.1:8080 + - http://0.0.0.0:8080 + - ${NGINX_HOST} +logging: + config: classpath:logback-spring.xml + diff --git a/docker/wvp/wvp/application.yml b/docker/wvp/wvp/application.yml new file mode 100755 index 000000000..4496fb6a2 --- /dev/null +++ b/docker/wvp/wvp/application.yml @@ -0,0 +1,5 @@ +spring: + application: + name: wvp + profiles: + active: docker \ No newline at end of file diff --git a/pom.xml b/pom.xml index 19d3e8396..2eb3ab962 100644 --- a/pom.xml +++ b/pom.xml @@ -187,7 +187,6 @@ 1.4.6 - org.springdoc @@ -200,13 +199,6 @@ 1.6.10 - - - org.springdoc - springdoc-openapi-ui - 1.6.10 - - com.github.xiaoymin knife4j-springdoc-ui @@ -250,12 +242,17 @@ com.alibaba.fastjson2 fastjson2 - 2.0.17 + 2.0.57 com.alibaba.fastjson2 fastjson2-extension - 2.0.17 + 2.0.57 + + + com.alibaba.fastjson2 + fastjson2-extension-spring5 + 2.0.57 diff --git a/run.sh b/run.sh new file mode 100644 index 000000000..f17040b7d --- /dev/null +++ b/run.sh @@ -0,0 +1,122 @@ +#!/bin/bash +# JDK路径 +export JAVA_HOME=/usr/local/java/jdk1.8.0_202 +export JRE_HOME=${JAVA_HOME}/jre +export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib +export PATH=${JAVA_HOME}/bin:$PATH + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +function log() { + message="[Polaris Log]: $1 " + case "$1" in + *"失败"* | *"错误"* | *"请使用 root 或 sudo 权限运行此脚本"*) + echo -e "${RED}${message}${NC}" 2>&1 | tee -a + ;; + *"成功"*) + echo -e "${GREEN}${message}${NC}" 2>&1 | tee -a + ;; + *"忽略"* | *"跳过"*) + echo -e "${YELLOW}${message}${NC}" 2>&1 | tee -a + ;; + *) + echo -e "${BLUE}${message}${NC}" 2>&1 | tee -a + ;; + esac +} + +echo +cat < /dev/null 2>&1 & + fi + log "流媒体服务开启成功" +} + +function stop() { + log "======================= 停止流媒体服务 =======================" + + PID="" + query() { + PID=$(ps -ef | grep java | grep $AppName | grep -v grep | awk '{print $2}') + } + query + if [ x"$PID" != x"" ]; then + log "进程PID: $PID" + kill -TERM $PID + log "$AppName (pid:$PID) exiting..." + while [ x"$PID" != x"" ]; do + sleep 1 + query + done + log "成功:$AppName exited." + else + log "忽略:进程不存在" + fi +} + +function status() { + log "======================= 运行状态 =======================" + log "" + + PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` + if [ $PID != 0 ]; then + log "进程PID: $PID" + log "$AppName is running..." + else + log "$AppName is not running..." + fi + log "" + log "========================================================" +} + +function restart() { + stop + sleep 3 + start +} + +case $1 in +start) + start + ;; +stop) + stop + ;; +restart) + restart + ;; +status) + status + ;; +*) ;; + +esac + diff --git a/src/main/java/com/genersoft/iot/vmp/common/GeneralCallback.java b/src/main/java/com/genersoft/iot/vmp/common/GeneralCallback.java deleted file mode 100644 index df07fac5e..000000000 --- a/src/main/java/com/genersoft/iot/vmp/common/GeneralCallback.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.genersoft.iot.vmp.common; - -public interface GeneralCallback{ - void run(int code, String msg, T data); -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java b/src/main/java/com/genersoft/iot/vmp/common/RemoteAddressInfo.java similarity index 90% rename from src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java rename to src/main/java/com/genersoft/iot/vmp/common/RemoteAddressInfo.java index 4107593fe..39478d812 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/common/RemoteAddressInfo.java @@ -1,4 +1,4 @@ -package com.genersoft.iot.vmp.gb28181.bean; +package com.genersoft.iot.vmp.common; public class RemoteAddressInfo { private String ip; diff --git a/src/main/java/com/genersoft/iot/vmp/common/SubscribeCallback.java b/src/main/java/com/genersoft/iot/vmp/common/SubscribeCallback.java new file mode 100644 index 000000000..5443b50e0 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/common/SubscribeCallback.java @@ -0,0 +1,7 @@ +package com.genersoft.iot.vmp.common; + +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; + +public interface SubscribeCallback{ + public void run(String deviceId, SipTransactionInfo transactionInfo); +} diff --git a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java index cee1993fa..2fa59b8ef 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java +++ b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java @@ -1,13 +1,13 @@ package com.genersoft.iot.vmp.common; -/** - * @description: 定义常量 +/** + * @description: 定义常量 * @author: swwheihei - * @date: 2019年5月30日 下午3:04:04 - * + * @date: 2019年5月30日 下午3:04:04 + * */ public class VideoManagerConstants { - + public static final String WVP_SERVER_PREFIX = "VMP_SIGNALLING_SERVER_INFO_"; public static final String WVP_SERVER_LIST = "VMP_SERVER_LIST"; @@ -22,10 +22,6 @@ public class VideoManagerConstants { public static final String INVITE_PREFIX = "VMP_GB_INVITE_INFO"; - public static final String PLATFORM_CATCH_PREFIX = "VMP_PLATFORM_CATCH_"; - - public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_PLATFORM_REGISTER_INFO_"; - public static final String SEND_RTP_PORT = "VM_SEND_RTP_PORT:"; public static final String SEND_RTP_INFO_CALLID = "VMP_SEND_RTP_INFO:CALL_ID:"; public static final String SEND_RTP_INFO_STREAM = "VMP_SEND_RTP_INFO:STREAM:"; diff --git a/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java index 67c926e61..5822d64c5 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java @@ -27,12 +27,12 @@ public class SipConfig { private String id; private String password; - + Integer ptzSpeed = 50; Integer registerTimeInterval = 120; private boolean alarm = false; - private long timeout = 150; + private long timeout = 1000; } diff --git a/src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java b/src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java deleted file mode 100644 index cb12754e6..000000000 --- a/src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.genersoft.iot.vmp.conf; - -import com.genersoft.iot.vmp.gb28181.bean.Platform; -import com.genersoft.iot.vmp.gb28181.bean.PlatformCatch; -import com.genersoft.iot.vmp.gb28181.service.IPlatformService; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.CommandLineRunner; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.List; - -/** - * 系统启动时控制上级平台重新注册 - * @author lin - */ -@Slf4j -@Component -@Order(value=13) -public class SipPlatformRunner implements CommandLineRunner { - - @Autowired - private IRedisCatchStorage redisCatchStorage; - - @Autowired - private IPlatformService platformService; - - @Autowired - private ISIPCommanderForPlatform sipCommanderForPlatform; - - @Autowired - private UserSetting userSetting; - - @Override - public void run(String... args) throws Exception { - // 获取所有启用的平台 - List parentPlatforms = platformService.queryEnablePlatformList(userSetting.getServerId()); - - for (Platform platform : parentPlatforms) { - - PlatformCatch platformCatchOld = redisCatchStorage.queryPlatformCatchInfo(platform.getServerGBId()); - - // 更新缓存 - PlatformCatch platformCatch = new PlatformCatch(); - platformCatch.setPlatform(platform); - platformCatch.setId(platform.getServerGBId()); - redisCatchStorage.updatePlatformCatchInfo(platformCatch); - if (platformCatchOld != null) { - // 取消订阅 - try { - log.info("[平台主动注销] {}({})", platform.getName(), platform.getServerGBId()); - sipCommanderForPlatform.unregister(platform, platformCatchOld.getSipTransactionInfo(), null, (eventResult)->{ - platformService.login(platform); - }); - } catch (Exception e) { - log.error("[命令发送失败] 国标级联 注销: {}", e.getMessage()); - platformService.offline(platform, true); - continue; - } - }else { - platformService.login(platform); - } - - // 设置平台离线 - platformService.offline(platform, false); - } - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java index ca346dfab..c4f2c4bae 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java @@ -190,5 +190,11 @@ public class UserSetting { */ private boolean autoRegisterPlatform = false; + /** + * 按需发送推流设备位置, 默认发送移动位置订阅时如果位置不变则不发送, 设置为false按照国标间隔持续发送 + */ + private boolean sendPositionOnDemand = true; + + } diff --git a/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisMsgListenConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisMsgListenConfig.java index f70a9e319..bc8b5f6a1 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisMsgListenConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisMsgListenConfig.java @@ -16,7 +16,7 @@ import org.springframework.data.redis.listener.RedisMessageListenerContainer; * @description:Redis中间件配置类,使用spring-data-redis集成,自动从application.yml中加载redis配置 * @author: swwheihei * @date: 2019年5月30日 上午10:58:25 - * + * */ @Configuration @Order(value=1) @@ -38,7 +38,6 @@ public class RedisMsgListenConfig { @Autowired private RedisCloseStreamMsgListener redisCloseStreamMsgListener; - @Autowired private RedisRpcConfig redisRpcConfig; @@ -49,7 +48,7 @@ public class RedisMsgListenConfig { /** * redis消息监听器容器 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器 * 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理 - * + * * @param connectionFactory * @return */ diff --git a/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisRpcConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisRpcConfig.java index b541f7448..b56818049 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisRpcConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisRpcConfig.java @@ -18,7 +18,6 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; -import javax.sip.message.Response; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AlarmChannelMessage.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AlarmChannelMessage.java index 7f50f4d37..4b3bb132a 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AlarmChannelMessage.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AlarmChannelMessage.java @@ -1,18 +1,23 @@ package com.genersoft.iot.vmp.gb28181.bean; +import lombok.Data; + /** * 通过redis分发报警消息 */ +@Data public class AlarmChannelMessage { /** - * 国标编号 + * 通道国标编号 */ private String gbId; + /** * 报警编号 */ private int alarmSn; + /** * 告警类型 */ @@ -22,36 +27,4 @@ public class AlarmChannelMessage { * 报警描述 */ private String alarmDescription; - - public String getGbId() { - return gbId; - } - - public void setGbId(String gbId) { - this.gbId = gbId; - } - - public int getAlarmSn() { - return alarmSn; - } - - public void setAlarmSn(int alarmSn) { - this.alarmSn = alarmSn; - } - - public int getAlarmType() { - return alarmType; - } - - public void setAlarmType(int alarmType) { - this.alarmType = alarmType; - } - - public String getAlarmDescription() { - return alarmDescription; - } - - public void setAlarmDescription(String alarmDescription) { - this.alarmDescription = alarmDescription; - } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java index 43c22cb2f..39e121fdf 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java @@ -86,6 +86,18 @@ public class CommonGBChannel { @Schema(description = "国标-纬度 WGS-84坐标系") private Double gbLatitude; + @Schema(description = "") + private Double gpsAltitude; + + @Schema(description = "") + private Double gpsSpeed; + + @Schema(description = "") + private Double gpsDirection; + + @Schema(description = "") + private String gpsTime; + @Schema(description = "国标-虚拟组织所属的业务分组ID") private String gbBusinessGroupId; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GroupTree.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GroupTree.java index 1f0f3658e..44789f0a2 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GroupTree.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GroupTree.java @@ -2,10 +2,12 @@ package com.genersoft.iot.vmp.gb28181.bean; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import lombok.EqualsAndHashCode; /** * 业务分组 */ +@EqualsAndHashCode(callSuper = true) @Data @Schema(description = "业务分组树") public class GroupTree extends Group{ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformKeepaliveCallback.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformKeepaliveCallback.java new file mode 100644 index 000000000..2e98fa830 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformKeepaliveCallback.java @@ -0,0 +1,5 @@ +package com.genersoft.iot.vmp.gb28181.bean; + +public interface PlatformKeepaliveCallback { + public void run(String platformServerGbId, int failCount); +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RegionTree.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RegionTree.java index 125bd3da7..10ef1ae02 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RegionTree.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RegionTree.java @@ -2,10 +2,12 @@ package com.genersoft.iot.vmp.gb28181.bean; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import lombok.EqualsAndHashCode; /** * 区域 */ +@EqualsAndHashCode(callSuper = true) @Data @Schema(description = "区域树") public class RegionTree extends Region { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipTransactionInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipTransactionInfo.java index 885843980..74c63e112 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipTransactionInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipTransactionInfo.java @@ -1,13 +1,17 @@ package com.genersoft.iot.vmp.gb28181.bean; import gov.nist.javax.sip.message.SIPResponse; +import lombok.Data; +@Data public class SipTransactionInfo { private String callId; private String fromTag; private String toTag; private String viaBranch; + private int expires; + private String user; // 自己是否媒体流发送者 private boolean asSender; @@ -31,43 +35,4 @@ public class SipTransactionInfo { public SipTransactionInfo() { } - public String getCallId() { - return callId; - } - - public void setCallId(String callId) { - this.callId = callId; - } - - public String getFromTag() { - return fromTag; - } - - public void setFromTag(String fromTag) { - this.fromTag = fromTag; - } - - public String getToTag() { - return toTag; - } - - public void setToTag(String toTag) { - this.toTag = toTag; - } - - public String getViaBranch() { - return viaBranch; - } - - public void setViaBranch(String viaBranch) { - this.viaBranch = viaBranch; - } - - public boolean isAsSender() { - return asSender; - } - - public void setAsSender(boolean asSender) { - this.asSender = asSender; - } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java index a15de224a..17a5284b3 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java @@ -1,19 +1,20 @@ package com.genersoft.iot.vmp.gb28181.bean; -import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.UserSetting; -import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; +import java.time.Duration; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ConcurrentHashMap; /** * @author lin */ +@Slf4j @Component public class SubscribeHolder { @@ -23,104 +24,97 @@ public class SubscribeHolder { @Autowired private UserSetting userSetting; - private final String taskOverduePrefix = "subscribe_overdue_"; - - private static ConcurrentHashMap catalogMap = new ConcurrentHashMap<>(); - private static ConcurrentHashMap mobilePositionMap = new ConcurrentHashMap<>(); + @Autowired + private RedisTemplate redisTemplate; + private final String prefix = "VMP_SUBSCRIBE_OVERDUE"; public void putCatalogSubscribe(String platformId, SubscribeInfo subscribeInfo) { - catalogMap.put(platformId, subscribeInfo); + log.info("[国标级联] 添加目录订阅,平台: {}, 有效期: {}", platformId, subscribeInfo.getExpires()); + + String key = String.format("%s_%s_%s_%s", prefix, userSetting.getServerId(), "catalog", platformId); if (subscribeInfo.getExpires() > 0) { - // 添加订阅到期 - String taskOverdueKey = taskOverduePrefix + "catalog_" + platformId; - // 添加任务处理订阅过期 - dynamicTask.startDelay(taskOverdueKey, () -> removeCatalogSubscribe(subscribeInfo.getId()), - subscribeInfo.getExpires() * 1000); + Duration duration = Duration.ofSeconds(subscribeInfo.getExpires()); + redisTemplate.opsForValue().set(key, subscribeInfo, duration); + }else { + redisTemplate.opsForValue().set(key, subscribeInfo); } } public SubscribeInfo getCatalogSubscribe(String platformId) { - return catalogMap.get(platformId); + String key = String.format("%s_%s_%s_%s", prefix, userSetting.getServerId(), "catalog", platformId); + return (SubscribeInfo)redisTemplate.opsForValue().get(key); } public void removeCatalogSubscribe(String platformId) { - - catalogMap.remove(platformId); - String taskOverdueKey = taskOverduePrefix + "catalog_" + platformId; - Runnable runnable = dynamicTask.get(taskOverdueKey); - if (runnable instanceof ISubscribeTask) { - ISubscribeTask subscribeTask = (ISubscribeTask) runnable; - subscribeTask.stop(null); - } - // 添加任务处理订阅过期 - dynamicTask.stop(taskOverdueKey); + String key = String.format("%s_%s_%s_%s", prefix, userSetting.getServerId(), "catalog", platformId); + redisTemplate.delete(key); } public void putMobilePositionSubscribe(String platformId, SubscribeInfo subscribeInfo, Runnable gpsTask) { - mobilePositionMap.put(platformId, subscribeInfo); - String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "MobilePosition_" + platformId; - // 添加任务处理GPS定时推送 - + log.info("[国标级联] 添加移动位置订阅,平台: {}, 有效期: {}s", platformId, subscribeInfo.getExpires()); + String key = String.format("%s_%s_%s_%s", prefix, userSetting.getServerId(), "mobilePosition", platformId); + if (subscribeInfo.getExpires() > 0) { + Duration duration = Duration.ofSeconds(subscribeInfo.getExpires()); + redisTemplate.opsForValue().set(key, subscribeInfo, duration); + }else { + redisTemplate.opsForValue().set(key, subscribeInfo); + } int cycleForCatalog; if (subscribeInfo.getGpsInterval() <= 0) { cycleForCatalog = 5; }else { cycleForCatalog = subscribeInfo.getGpsInterval(); } - dynamicTask.startCron(key, gpsTask, + dynamicTask.startCron( + key, + () -> { + SubscribeInfo subscribe = getMobilePositionSubscribe(platformId); + if (subscribe != null) { + gpsTask.run(); + }else { + dynamicTask.stop(key); + } + }, cycleForCatalog * 1000); - String taskOverdueKey = taskOverduePrefix + "MobilePosition_" + platformId; - if (subscribeInfo.getExpires() > 0) { - // 添加任务处理订阅过期 - dynamicTask.startDelay(taskOverdueKey, () -> { - removeMobilePositionSubscribe(subscribeInfo.getId()); - }, - subscribeInfo.getExpires() * 1000); - } + } public SubscribeInfo getMobilePositionSubscribe(String platformId) { - return mobilePositionMap.get(platformId); + String key = String.format("%s_%s_%s_%s", prefix, userSetting.getServerId(), "mobilePosition", platformId); + return (SubscribeInfo)redisTemplate.opsForValue().get(key); } public void removeMobilePositionSubscribe(String platformId) { - mobilePositionMap.remove(platformId); - String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "MobilePosition_" + platformId; - // 结束任务处理GPS定时推送 - dynamicTask.stop(key); - String taskOverdueKey = taskOverduePrefix + "MobilePosition_" + platformId; - Runnable runnable = dynamicTask.get(taskOverdueKey); - if (runnable instanceof ISubscribeTask) { - ISubscribeTask subscribeTask = (ISubscribeTask) runnable; - subscribeTask.stop(null); - } - // 添加任务处理订阅过期 - dynamicTask.stop(taskOverdueKey); + String key = String.format("%s_%s_%s_%s", prefix, userSetting.getServerId(), "mobilePosition", platformId); + redisTemplate.delete(key); } - public List getAllCatalogSubscribePlatform() { - List platforms = new ArrayList<>(); - if(catalogMap.size() > 0) { - for (String key : catalogMap.keySet()) { - platforms.add(catalogMap.get(key).getId()); + public List getAllCatalogSubscribePlatform(List platformList) { + if (platformList == null || platformList.isEmpty()) { + return new ArrayList<>(); + } + List result = new ArrayList<>(); + for (Platform platform : platformList) { + String key = String.format("%s_%s_%s_%s", prefix, userSetting.getServerId(), "catalog", platform.getServerGBId()); + if (redisTemplate.hasKey(key)) { + result.add(platform.getServerGBId()); } } - return platforms; + return result; } - public List getAllMobilePositionSubscribePlatform() { - List platforms = new ArrayList<>(); - if(!mobilePositionMap.isEmpty()) { - for (String key : mobilePositionMap.keySet()) { - platforms.add(mobilePositionMap.get(key).getId()); + public List getAllMobilePositionSubscribePlatform(List platformList) { + if (platformList == null || platformList.isEmpty()) { + return new ArrayList<>(); + } + List result = new ArrayList<>(); + for (Platform platform : platformList) { + String key = String.format("%s_%s_%s_%s", prefix, userSetting.getServerId(), "mobilePosition", platform.getServerGBId()); + if (redisTemplate.hasKey(key)) { + result.add(platform.getServerGBId()); } } - return platforms; - } - - public void removeAllSubscribe(String platformId) { - removeMobilePositionSubscribe(platformId); - removeCatalogSubscribe(platformId); + return result; } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java index a131ccb43..5820cb67c 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java @@ -1,36 +1,19 @@ package com.genersoft.iot.vmp.gb28181.bean; -import gov.nist.javax.sip.message.SIPRequest; import gov.nist.javax.sip.message.SIPResponse; import lombok.Data; -import javax.sip.header.*; +import javax.sip.header.EventHeader; import java.util.UUID; @Data public class SubscribeInfo { - - public SubscribeInfo(SIPRequest request, String id) { - this.id = id; - this.request = request; - this.expires = request.getExpires().getExpires(); - EventHeader eventHeader = (EventHeader)request.getHeader(EventHeader.NAME); - this.eventId = eventHeader.getEventId(); - this.eventType = eventHeader.getEventType(); - - } - - public SubscribeInfo() { - } - private String id; - - private SIPRequest request; private int expires; private String eventId; private String eventType; - private SIPResponse response; + private SipTransactionInfo transactionInfo; /** * 以下为可选字段 @@ -55,6 +38,16 @@ public class SubscribeInfo { private String simulatedCallId; + public static SubscribeInfo getInstance(SIPResponse response, String id, int expires, EventHeader eventHeader){ + SubscribeInfo subscribeInfo = new SubscribeInfo(); + subscribeInfo.id = id; + subscribeInfo.transactionInfo = new SipTransactionInfo(response); + + subscribeInfo.expires = expires; + subscribeInfo.eventId = eventHeader.getEventId(); + subscribeInfo.eventType = eventHeader.getEventType(); + return subscribeInfo; + } public static SubscribeInfo buildSimulated(String platFormServerId, String platFormServerIp){ SubscribeInfo subscribeInfo = new SubscribeInfo(); subscribeInfo.setId(platFormServerId); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/CommonChannelController.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/CommonChannelController.java index ef81848fe..bb6d2fd34 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/CommonChannelController.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/CommonChannelController.java @@ -148,7 +148,6 @@ public class CommonChannelController { @Parameter(name = "query", description = "查询内容") @Parameter(name = "online", description = "是否在线") @Parameter(name = "channelType", description = "通道类型, 0:国标设备,1:推流设备,2:拉流代理") - @Parameter(name = "civilCode", description = "行政区划") @GetMapping("/civilCode/unusual/list") public PageInfo queryListByCivilCodeForUnusual(int page, int count, @RequestParam(required = false) String query, @@ -160,14 +159,36 @@ public class CommonChannelController { return channelService.queryListByCivilCodeForUnusual(page, count, query, online, channelType); } - @Operation(summary = "清除存在行政区划但无法挂载的通道列表", security = @SecurityRequirement(name = JwtUtils.HEADER)) - @Parameter(name = "param", description = "当前页", required = true) - @GetMapping("/civilCode/unusual/clear") - public void queryListByCivilCodeForUnusual(ChannelToRegionParam param){ + + @Operation(summary = "存在父节点编号但无法挂载的通道列表", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "page", description = "当前页", required = true) + @Parameter(name = "count", description = "每页查询数量", required = true) + @Parameter(name = "query", description = "查询内容") + @Parameter(name = "online", description = "是否在线") + @Parameter(name = "channelType", description = "通道类型, 0:国标设备,1:推流设备,2:拉流代理") + @GetMapping("/parent/unusual/list") + public PageInfo queryListByParentForUnusual(int page, int count, + @RequestParam(required = false) String query, + @RequestParam(required = false) Boolean online, + @RequestParam(required = false) Integer channelType){ if (ObjectUtils.isEmpty(query)){ query = null; } - return channelService.queryListByCivilCodeForUnusual(page, count, query, online, channelType); + return channelService.queryListByParentForUnusual(page, count, query, online, channelType); + } + + @Operation(summary = "清除存在行政区划但无法挂载的通道列表", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "param", description = "清理参数, all为true清理所有异常数据。 否则按照传入的设备Id清理", required = true) + @PostMapping("/civilCode/unusual/clear") + public void clearChannelCivilCode(@RequestBody ChannelToRegionParam param){ + channelService.clearChannelCivilCode(param.getAll(), param.getChannelIds()); + } + + @Operation(summary = "清除存在分组节点但无法挂载的通道列表", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "param", description = "清理参数, all为true清理所有异常数据。 否则按照传入的设备Id清理", required = true) + @PostMapping("/parent/unusual/clear") + public void clearChannelParent(@RequestBody ChannelToRegionParam param){ + channelService.clearChannelParent(param.getAll(), param.getChannelIds()); } @Operation(summary = "获取关联业务分组通道列表", security = @SecurityRequirement(name = JwtUtils.HEADER)) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceQuery.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceQuery.java index c18df8f59..e98a93a3f 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceQuery.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceQuery.java @@ -11,9 +11,6 @@ import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService; import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.service.IInviteStreamService; -import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; -import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask; -import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcService; @@ -40,9 +37,6 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; @Tag(name = "国标设备查询", description = "国标设备查询") @SuppressWarnings("rawtypes") @@ -79,7 +73,7 @@ public class DeviceQuery { @Parameter(name = "deviceId", description = "设备国标编号", required = true) @GetMapping("/devices/{deviceId}") public Device devices(@PathVariable String deviceId){ - + return deviceService.getDeviceByDeviceId(deviceId); } @@ -144,28 +138,10 @@ public class DeviceQuery { } // 清除redis记录 - boolean isSuccess = deviceService.delete(deviceId); - if (isSuccess) { - inviteStreamService.clearInviteInfo(deviceId); - // 停止此设备的订阅更新 - Set allKeys = dynamicTask.getAllKeys(); - for (String key : allKeys) { - if (key.startsWith(deviceId)) { - Runnable runnable = dynamicTask.get(key); - if (runnable instanceof ISubscribeTask) { - ISubscribeTask subscribeTask = (ISubscribeTask) runnable; - subscribeTask.stop(null); - } - dynamicTask.stop(key); - } - } - JSONObject json = new JSONObject(); - json.put("deviceId", deviceId); - return json.toString(); - } else { - log.warn("设备信息删除API调用失败!"); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备信息删除API调用失败!"); - } + deviceService.delete(deviceId); + JSONObject json = new JSONObject(); + json.put("deviceId", deviceId); + return json.toString(); } @Operation(summary = "分页查询子目录通道", security = @SecurityRequirement(name = JwtUtils.HEADER)) @@ -355,28 +331,6 @@ public class DeviceQuery { return wvpResult; } - @GetMapping("/{deviceId}/subscribe_info") - @Operation(summary = "获取设备的订阅状态", security = @SecurityRequirement(name = JwtUtils.HEADER)) - @Parameter(name = "deviceId", description = "设备国标编号", required = true) - public WVPResult> getSubscribeInfo(@PathVariable String deviceId) { - Set allKeys = dynamicTask.getAllKeys(); - Map dialogStateMap = new HashMap<>(); - for (String key : allKeys) { - if (key.startsWith(deviceId)) { - ISubscribeTask subscribeTask = (ISubscribeTask)dynamicTask.get(key); - if (subscribeTask instanceof CatalogSubscribeTask) { - dialogStateMap.put("catalog", 1); - }else if (subscribeTask instanceof MobilePositionSubscribeTask) { - dialogStateMap.put("mobilePosition", 1); - } - } - } - WVPResult> wvpResult = new WVPResult<>(); - wvpResult.setCode(0); - wvpResult.setData(dialogStateMap); - return wvpResult; - } - @GetMapping("/snap/{deviceId}/{channelId}") @Operation(summary = "请求截图") @Parameter(name = "deviceId", description = "设备国标编号", required = true) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/MobilePositionController.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/MobilePositionController.java index 1c3406f85..7ef963509 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/MobilePositionController.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/MobilePositionController.java @@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; import com.genersoft.iot.vmp.service.IMobilePositionService; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.github.pagehelper.util.StringUtil; @@ -37,10 +37,10 @@ public class MobilePositionController { @Autowired private IMobilePositionService mobilePositionService; - + @Autowired - private SIPCommander cmder; - + private ISIPCommander cmder; + @Autowired private DeferredResultHolder resultHolder; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/RegionController.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/RegionController.java index 3fd7f79a3..d49c28626 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/RegionController.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/RegionController.java @@ -124,4 +124,20 @@ public class RegionController { public void sync(){ regionService.syncFromChannel(); } + + @Operation(summary = "根据行政区划编号从文件中查询层级和描述") + @ResponseBody + @GetMapping("/description") + public String getDescription(String civilCode){ + return regionService.getDescription(civilCode); + } + + @Operation(summary = "根据行政区划编号从文件中查询层级并添加") + @ResponseBody + @GetMapping("/addByCivilCode") + public void addByCivilCode(String civilCode){ + regionService.addByCivilCode(civilCode); + } + + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java index c9468a027..efa826c36 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.dao; import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.dao.provider.ChannelProvider; +import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.streamPush.bean.StreamPush; import org.apache.ibatis.annotations.*; import org.springframework.stereotype.Repository; @@ -307,6 +308,14 @@ public interface CommonGBChannelMapper { " "}) int removeCivilCodeByChannels(List channelList); + @Update(value = {" "}) + int removeCivilCodeByChannelIds(List channelIdList); + @SelectProvider(type = ChannelProvider.class, method = "queryByCivilCode") List queryByCivilCode(@Param("civilCode") String civilCode); @@ -443,13 +452,18 @@ public interface CommonGBChannelMapper { List queryListByStreamPushList(@Param("dataType") Integer dataType, List streamPushList); @Update(value = {" "}) - void updateGpsByDeviceIdForStreamPush(@Param("dataType") Integer dataType, List channels); + void updateGpsByDeviceId(List gpsMsgInfoList); @SelectProvider(type = ChannelProvider.class, method = "queryList") List queryList(@Param("query") String query, @Param("online") Boolean online, @@ -548,4 +562,20 @@ public interface CommonGBChannelMapper { @SelectProvider(type = ChannelProvider.class, method = "queryListByCivilCodeForUnusual") List queryListByCivilCodeForUnusual(@Param("query") String query, @Param("online") Boolean online, @Param("dataType")Integer dataType); + @SelectProvider(type = ChannelProvider.class, method = "queryAllForUnusualCivilCode") + List queryAllForUnusualCivilCode(); + + @SelectProvider(type = ChannelProvider.class, method = "queryListByParentForUnusual") + List queryListByParentForUnusual(@Param("query") String query, @Param("online") Boolean online, @Param("dataType")Integer dataType); + + @SelectProvider(type = ChannelProvider.class, method = "queryAllForUnusualParent") + List queryAllForUnusualParent(); + + @Update(value = {" "}) + void removeParentIdByChannelIds(List channelIdsForClear); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceMapper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceMapper.java index 06a534821..b999fecd1 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceMapper.java @@ -123,23 +123,27 @@ public interface DeviceMapper { @Update(value = {" "}) int update(Device device); @@ -381,7 +385,7 @@ public interface DeviceMapper { " OR device_id LIKE concat('%',#{query},'%') escape '/' " + " OR ip LIKE concat('%',#{query},'%') escape '/')" + " " + - " order by create_time desc "+ + " order by create_time desc, device_id " + " ") List getDeviceList(@Param("dataType") Integer dataType, @Param("query") String query, @Param("status") Boolean status); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/PlatformChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/PlatformChannelMapper.java index c69a32d5c..c437eee0f 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/PlatformChannelMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/PlatformChannelMapper.java @@ -262,6 +262,10 @@ public interface PlatformChannelMapper { " wdc.data_device_id,\n" + " wdc.create_time,\n" + " wdc.update_time,\n" + + " wdc.gps_altitude,\n" + + " wdc.gps_speed,\n" + + " wdc.gps_direction,\n" + + " wdc.gps_time,\n" + " coalesce(wpgc.custom_device_id, wdc.gb_device_id, wdc.device_id) as gb_device_id,\n" + " coalesce(wpgc.custom_name, wdc.gb_name, wdc.name) as gb_name,\n" + " coalesce(wpgc.custom_manufacturer, wdc.gb_manufacturer, wdc.manufacturer) as gb_manufacturer,\n" + diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/PlatformMapper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/PlatformMapper.java index 5218537f9..bb3c0f0e2 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/PlatformMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/PlatformMapper.java @@ -78,7 +78,7 @@ public interface PlatformMapper { List queryList(@Param("query") String query); @Select("SELECT * FROM wvp_platform WHERE server_id=#{serverId} and enable=#{enable} ") - List queryEnableParentPlatformList(@Param("serverId") String serverId, @Param("enable") boolean enable); + List queryEnableParentPlatformListByServerId(@Param("serverId") String serverId, @Param("enable") boolean enable); @Select("SELECT * FROM wvp_platform WHERE enable=true and as_message_channel=true") List queryEnablePlatformListWithAsMessageChannel(); @@ -89,12 +89,22 @@ public interface PlatformMapper { @Select("SELECT * FROM wvp_platform WHERE id=#{id}") Platform query(int id); - @Update("UPDATE wvp_platform SET status=#{online} WHERE server_gb_id=#{platformGbID}" ) - int updateStatus(@Param("platformGbID") String platformGbID, @Param("online") boolean online); + @Update("UPDATE wvp_platform SET status=#{online}, server_id = #{serverId} WHERE id=#{id}" ) + int updateStatus(@Param("id") int id, @Param("online") boolean online, @Param("serverId") String serverId); @Select("SELECT server_id FROM wvp_platform WHERE enable=true and server_id != #{serverId} group by server_id") List queryServerIdsWithEnableAndNotInServer(@Param("serverId") String serverId); @Select("SELECT * FROM wvp_platform WHERE server_id = #{serverId}") List queryByServerId(@Param("serverId") String serverId); + + @Select("SELECT * FROM wvp_platform ") + List queryAll(); + + @Select("SELECT * FROM wvp_platform WHERE enable=true and server_id = #{serverId}") + List queryServerIdsWithEnableAndServer(@Param("serverId") String serverId); + + @Update("UPDATE wvp_platform SET status=false where server_id = #{serverId}" ) + void offlineAll(@Param("serverId") String serverId); + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/RegionMapper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/RegionMapper.java index f31146721..c9b9cfac8 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/RegionMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/RegionMapper.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.gb28181.dao; +import com.genersoft.iot.vmp.common.CivilCodePo; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.Region; import com.genersoft.iot.vmp.gb28181.bean.RegionTree; @@ -179,4 +180,12 @@ public interface RegionMapper { " ") Set queryNotShareRegionForPlatformByRegionList(Set allRegion, @Param("platformId") Integer platformId); + + @Select(" ") + Set queryInCivilCodePoList(List civilCodePoList); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/ChannelProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/ChannelProvider.java index b4d006d05..0941cf2dc 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/ChannelProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/ChannelProvider.java @@ -373,7 +373,7 @@ public class ChannelProvider { StringBuilder sqlBuild = new StringBuilder(); sqlBuild.append(BASE_SQL); - sqlBuild.append(" where channel_type = 0 and data_type = #{dataType} and data_device_id in ( "); + sqlBuild.append(" where channel_type = 0 and data_type = #{dataType} and data_device_id in ( "); Collection ids = (Collection)params.get("streamPushList"); boolean first = true; for (StreamPush streamPush : ids) { @@ -431,4 +431,45 @@ public class ChannelProvider { } return sqlBuild.toString(); } + + public String queryListByParentForUnusual(Map params ){ + StringBuilder sqlBuild = new StringBuilder(); + sqlBuild.append(BASE_SQL_TABLE_NAME); + sqlBuild.append(" left join (select wcg.device_id from wvp_common_group wcg) temp on temp.device_id = coalesce(wdc.gb_parent_id, wdc.parent_id)" + + " where coalesce(wdc.gb_parent_id, wdc.parent_id) is not null and temp.device_id is null "); + sqlBuild.append(" AND wdc.channel_type = 0 "); + if (params.get("query") != null) { + sqlBuild.append(" AND (coalesce(wdc.gb_device_id, wdc.device_id) LIKE concat('%',#{query},'%') escape '/'" + + " OR coalesce(wdc.gb_name, wdc.name) LIKE concat('%',#{query},'%') escape '/' )") + ; + } + if (params.get("online") != null && (Boolean)params.get("online")) { + sqlBuild.append(" AND coalesce(wdc.gb_status, wdc.status) = 'ON'"); + } + if (params.get("online") != null && !(Boolean)params.get("online")) { + sqlBuild.append(" AND coalesce(wdc.gb_status, wdc.status) = 'OFF'"); + } + if (params.get("dataType") != null) { + sqlBuild.append(" AND wdc.data_type = #{dataType}"); + } + return sqlBuild.toString(); + } + + public String queryAllForUnusualCivilCode(Map params ){ + StringBuilder sqlBuild = new StringBuilder(); + sqlBuild.append("select wdc.id from wvp_device_channel wdc "); + sqlBuild.append(" left join (select wcr.device_id from wvp_common_region wcr) temp on temp.device_id = coalesce(wdc.gb_civil_code, wdc.civil_code)" + + " where coalesce(wdc.gb_civil_code, wdc.civil_code) is not null and temp.device_id is null "); + sqlBuild.append(" AND wdc.channel_type = 0 "); + return sqlBuild.toString(); + } + + public String queryAllForUnusualParent(Map params ){ + StringBuilder sqlBuild = new StringBuilder(); + sqlBuild.append("select wdc.id from wvp_device_channel wdc "); + sqlBuild.append(" left join (select wcg.device_id from wvp_common_group wcg) temp on temp.device_id = coalesce(wdc.gb_parent_id, wdc.parent_id)" + + " where coalesce(wdc.gb_parent_id, wdc.parent_id) is not null and temp.device_id is null "); + sqlBuild.append(" AND wdc.channel_type = 0 "); + return sqlBuild.toString(); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/DeviceChannelProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/DeviceChannelProvider.java index eece8399e..9578682be 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/DeviceChannelProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/DeviceChannelProvider.java @@ -101,6 +101,7 @@ public class DeviceChannelProvider { } sqlBuild.append(" )"); } + sqlBuild.append("ORDER BY device_id"); return sqlBuild.toString(); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java index 9aa75b712..018abc5c6 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java @@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOfflineEvent; import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOnlineEvent; import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcService; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Component; @@ -21,11 +22,12 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -/** +/** * @description:Event事件通知推送器,支持推送在线事件、离线事件 * @author: swwheihei - * @date: 2020年5月6日 上午11:30:50 + * @date: 2020年5月6日 上午11:30:50 */ +@Slf4j @Component public class EventPublisher { @@ -72,12 +74,7 @@ public class EventPublisher { } public void catalogEventPublish(Platform platform, List deviceChannels, String type, boolean share) { if (platform != null && !userSetting.getServerId().equals(platform.getServerId())) { - // 指定了上级平台的推送,则发送到指定的设备,未指定的则全部发送, 接收后各自处理自己的 - CatalogEvent outEvent = new CatalogEvent(this); - outEvent.setChannels(deviceChannels); - outEvent.setType(type); - outEvent.setPlatform(platform); - redisRpcService.catalogEventPublish(platform.getServerId(), outEvent); + log.info("[国标级联] 目录状态推送, 此上级平台由其他服务处理,消息已经忽略"); return; } CatalogEvent outEvent = new CatalogEvent(this); @@ -96,12 +93,11 @@ public class EventPublisher { } outEvent.setChannels(channels); outEvent.setType(type); - outEvent.setPlatform(platform); - applicationEventPublisher.publishEvent(outEvent); - if (platform == null && share) { - // 如果没指定上级平台,则推送消息到所有在线的wvp处理自己含有的平台的目录更新 - redisRpcService.catalogEventPublish(null, outEvent); + if (platform != null) { + outEvent.setPlatform(platform); } + applicationEventPublisher.publishEvent(outEvent); + } public void mobilePositionEventPublish(MobilePosition mobilePosition) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/sip/SipEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/sip/SipEvent.java index be20a54e2..0bca7cd13 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/sip/SipEvent.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/sip/SipEvent.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.gb28181.event.sip; +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import lombok.Data; import org.jetbrains.annotations.NotNull; @@ -27,6 +28,8 @@ public class SipEvent implements Delayed { */ private long delay; + private SipTransactionInfo sipTransactionInfo; + public static SipEvent getInstance(String key, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent, long delay) { SipEvent sipEvent = new SipEvent(); sipEvent.setKey(key); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java index 08a329022..69b55445c 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java @@ -8,7 +8,6 @@ import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo; import com.genersoft.iot.vmp.gb28181.service.IPlatformChannelService; import com.genersoft.iot.vmp.gb28181.service.IPlatformService; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; -import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; @@ -17,7 +16,10 @@ import org.springframework.stereotype.Component; import javax.sip.InvalidArgumentException; import javax.sip.SipException; import java.text.ParseException; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * catalog事件 @@ -26,6 +28,9 @@ import java.util.*; @Component public class CatalogEventLister implements ApplicationListener { + @Autowired + private IPlatformService platformService; + @Autowired private IPlatformChannelService platformChannelService; @@ -35,32 +40,45 @@ public class CatalogEventLister implements ApplicationListener { @Autowired private SubscribeHolder subscribeHolder; + @Autowired + private UserSetting userSetting; + @Override public void onApplicationEvent(CatalogEvent event) { SubscribeInfo subscribe = null; Platform parentPlatform = null; - - Map> parentPlatformMap = new HashMap<>(); + log.info("[Catalog事件: {}] 通道数量: {}", event.getType(), event.getChannels().size()); + Map> platformMap = new HashMap<>(); Map channelMap = new HashMap<>(); if (event.getPlatform() != null) { parentPlatform = event.getPlatform(); + if (parentPlatform.getServerGBId() == null) { + log.info("[Catalog事件: {}] 平台服务国标编码未找到", event.getType()); + return; + } subscribe = subscribeHolder.getCatalogSubscribe(parentPlatform.getServerGBId()); if (subscribe == null) { + log.info("[Catalog事件: {}] 未订阅目录事件", event.getType()); return; } }else { + List allPlatform = platformService.queryAll(userSetting.getServerId()); // 获取所用订阅 - List platforms = subscribeHolder.getAllCatalogSubscribePlatform(); + List platforms = subscribeHolder.getAllCatalogSubscribePlatform(allPlatform); if (event.getChannels() != null) { if (!platforms.isEmpty()) { for (CommonGBChannel deviceChannel : event.getChannels()) { List parentPlatformsForGB = platformChannelService.queryPlatFormListByChannelDeviceId( deviceChannel.getGbId(), platforms); - parentPlatformMap.put(deviceChannel.getGbDeviceId(), parentPlatformsForGB); + platformMap.put(deviceChannel.getGbDeviceId(), parentPlatformsForGB); channelMap.put(deviceChannel.getGbDeviceId(), deviceChannel); } + }else { + log.info("[Catalog事件: {}] 未订阅目录事件", event.getType()); } + }else { + log.info("[Catalog事件: {}] 事件内通道数为0", event.getType()); } } switch (event.getType()) { @@ -69,32 +87,32 @@ public class CatalogEventLister implements ApplicationListener { case CatalogEvent.DEL: if (parentPlatform != null) { - List deviceChannelList = new ArrayList<>(); + List channels = new ArrayList<>(); if (event.getChannels() != null) { - deviceChannelList.addAll(event.getChannels()); + channels.addAll(event.getChannels()); } - if (!deviceChannelList.isEmpty()) { - log.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), parentPlatform.getServerGBId(), deviceChannelList.size()); + if (!channels.isEmpty()) { + log.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), parentPlatform.getServerGBId(), channels.size()); try { - sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), parentPlatform, deviceChannelList, subscribe, null); + sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), parentPlatform, channels, subscribe, null); } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | IllegalAccessException e) { log.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); } } - }else if (!parentPlatformMap.keySet().isEmpty()) { - for (String gbId : parentPlatformMap.keySet()) { - List parentPlatforms = parentPlatformMap.get(gbId); - if (parentPlatforms != null && !parentPlatforms.isEmpty()) { - for (Platform platform : parentPlatforms) { + }else if (!platformMap.keySet().isEmpty()) { + for (String serverGbId : platformMap.keySet()) { + List platformList = platformMap.get(serverGbId); + if (platformList != null && !platformList.isEmpty()) { + for (Platform platform : platformList) { SubscribeInfo subscribeInfo = subscribeHolder.getCatalogSubscribe(platform.getServerGBId()); if (subscribeInfo == null) { continue; } - log.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId); + log.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), serverGbId); List deviceChannelList = new ArrayList<>(); CommonGBChannel deviceChannel = new CommonGBChannel(); - deviceChannel.setGbDeviceId(gbId); + deviceChannel.setGbDeviceId(serverGbId); deviceChannelList.add(deviceChannel); try { sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), platform, deviceChannelList, subscribeInfo, null); @@ -103,6 +121,8 @@ public class CatalogEventLister implements ApplicationListener { log.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); } } + }else { + log.info("[Catalog事件: {}] 未找到上级平台: {}", event.getType(), serverGbId); } } } @@ -127,9 +147,9 @@ public class CatalogEventLister implements ApplicationListener { log.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); } } - }else if (!parentPlatformMap.keySet().isEmpty()) { - for (String gbId : parentPlatformMap.keySet()) { - List parentPlatforms = parentPlatformMap.get(gbId); + }else if (!platformMap.keySet().isEmpty()) { + for (String gbId : platformMap.keySet()) { + List parentPlatforms = platformMap.get(gbId); if (parentPlatforms != null && !parentPlatforms.isEmpty()) { for (Platform platform : parentPlatforms) { SubscribeInfo subscribeInfo = subscribeHolder.getCatalogSubscribe(platform.getServerGBId()); @@ -156,4 +176,4 @@ public class CatalogEventLister implements ApplicationListener { } } } - \ No newline at end of file + diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/mobilePosition/MobilePositionEventLister.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/mobilePosition/MobilePositionEventLister.java index 40dc6c853..7b06f07fc 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/mobilePosition/MobilePositionEventLister.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/mobilePosition/MobilePositionEventLister.java @@ -1,10 +1,12 @@ package com.genersoft.iot.vmp.gb28181.event.subscribe.mobilePosition; +import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.Platform; import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo; import com.genersoft.iot.vmp.gb28181.service.IPlatformChannelService; +import com.genersoft.iot.vmp.gb28181.service.IPlatformService; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderForPlatform; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import lombok.extern.slf4j.Slf4j; @@ -24,6 +26,9 @@ import java.util.List; @Component public class MobilePositionEventLister implements ApplicationListener { + @Autowired + private IPlatformService platformService; + @Autowired private IPlatformChannelService platformChannelService; @@ -33,14 +38,17 @@ public class MobilePositionEventLister implements ApplicationListener allPlatforms = platformService.queryAll(userSetting.getServerId()); // 获取所用订阅 - List platforms = subscribeHolder.getAllMobilePositionSubscribePlatform(); + List platforms = subscribeHolder.getAllMobilePositionSubscribePlatform(allPlatforms); if (platforms.isEmpty()) { return; } @@ -65,4 +73,3 @@ public class MobilePositionEventLister implements ApplicationListener queryListByStreamPushList(List streamPushList); - void updateGpsByDeviceIdForStreamPush(List channels); - PageInfo queryList(int page, int count, String query, Boolean online, Boolean hasRecordPlan, Integer channelType); void queryRecordInfo(CommonGBChannel channel, String startTime, String endTime, ErrorCallback callback); PageInfo queryListByCivilCodeForUnusual(int page, int count, String query, Boolean online, Integer channelType); + + void clearChannelCivilCode(Boolean all, List channelIds); + + PageInfo queryListByParentForUnusual(int page, int count, String query, Boolean online, Integer channelType); + + void clearChannelParent(Boolean all, List channelIds); + + void updateGPSFromGPSMsgInfo(List gpsMsgInfoList); + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformChannelService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformChannelService.java index 0d97aa297..0151b63a5 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformChannelService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformChannelService.java @@ -48,4 +48,6 @@ public interface IPlatformChannelService { void checkRegionAdd(List channelList); void checkRegionRemove(List channelList, List regionList); + + List queryByPlatformBySharChannelId(String gbId); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformService.java index a6c2b2466..b0bea7d14 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformService.java @@ -53,13 +53,7 @@ public interface IPlatformService { * 平台离线 * @param parentPlatform 平台信息 */ - void offline(Platform parentPlatform, boolean stopRegisterTask); - - /** - * 向上级平台发起注册 - * @param parentPlatform - */ - void login(Platform parentPlatform); + void offline(Platform parentPlatform); /** * 向上级平台发送位置订阅 @@ -85,4 +79,7 @@ public interface IPlatformService { List queryEnablePlatformList(String serverId); void delete(Integer platformId, CommonCallback callback); + + List queryAll(String serverId); + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IRegionService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IRegionService.java index 0bd8700db..6a2b9296c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IRegionService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IRegionService.java @@ -36,4 +36,8 @@ public interface IRegionService { boolean batchAdd(List regionList); List getPath(String deviceId); + + String getDescription(String civilCode); + + void addByCivilCode(String civilCode); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceServiceImpl.java index c36d94800..47dbfc931 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceServiceImpl.java @@ -15,9 +15,11 @@ import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.service.IInviteStreamService; import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager; -import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; -import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask; -import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask; +import com.genersoft.iot.vmp.gb28181.task.deviceSubscribe.SubscribeTask; +import com.genersoft.iot.vmp.gb28181.task.deviceSubscribe.SubscribeTaskInfo; +import com.genersoft.iot.vmp.gb28181.task.deviceSubscribe.SubscribeTaskRunner; +import com.genersoft.iot.vmp.gb28181.task.deviceSubscribe.impl.SubscribeTaskForCatalog; +import com.genersoft.iot.vmp.gb28181.task.deviceSubscribe.impl.SubscribeTaskForMobilPosition; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler; import com.genersoft.iot.vmp.media.bean.MediaServer; @@ -32,13 +34,18 @@ import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; +import gov.nist.javax.sip.message.SIPResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.core.annotation.Order; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import javax.sip.InvalidArgumentException; +import javax.sip.ResponseEvent; import javax.sip.SipException; import javax.validation.constraints.NotNull; import java.text.ParseException; @@ -53,7 +60,8 @@ import java.util.concurrent.TimeUnit; */ @Slf4j @Service -public class DeviceServiceImpl implements IDeviceService { +@Order(value=16) +public class DeviceServiceImpl implements IDeviceService, CommandLineRunner { @Autowired private DynamicTask dynamicTask; @@ -100,10 +108,46 @@ public class DeviceServiceImpl implements IDeviceService { @Autowired private IRedisRpcService redisRpcService; + @Autowired + private SubscribeTaskRunner subscribeTaskRunner; + private Device getDeviceByDeviceIdFromDb(String deviceId) { return deviceMapper.getDeviceByDeviceId(deviceId); } + @Override + public void run(String... args) throws Exception { + // TODO 处理设备离线 + + // 处理订阅任务 + List taskInfoList = subscribeTaskRunner.getAllTaskInfo(); + if (!taskInfoList.isEmpty()) { + for (SubscribeTaskInfo taskInfo : taskInfoList) { + if (taskInfo == null) { + continue; + } + Device device = getDeviceByDeviceId(taskInfo.getDeviceId()); + if (device == null || !device.isOnLine()) { + subscribeTaskRunner.removeSubscribe(taskInfo.getKey()); + continue; + } + if (SubscribeTaskForCatalog.name.equals(taskInfo.getName())) { + device.setSubscribeCycleForCatalog((int)taskInfo.getExpireTime()); + SubscribeTask subscribeTask = SubscribeTaskForCatalog.getInstance(device, this::catalogSubscribeExpire, taskInfo.getTransactionInfo()); + if (subscribeTask != null) { + subscribeTaskRunner.addSubscribe(subscribeTask); + } + }else if (SubscribeTaskForMobilPosition.name.equals(taskInfo.getName())) { + device.setSubscribeCycleForMobilePosition((int)taskInfo.getExpireTime()); + SubscribeTask subscribeTask = SubscribeTaskForMobilPosition.getInstance(device, this::mobilPositionSubscribeExpire, taskInfo.getTransactionInfo()); + if (subscribeTask != null) { + subscribeTaskRunner.addSubscribe(subscribeTask); + } + } + } + } + } + @Override public void online(Device device, SipTransactionInfo sipTransactionInfo) { log.info("[设备上线] deviceId:{}->{}:{}", device.getDeviceId(), device.getIp(), device.getPort()); @@ -148,6 +192,7 @@ public class DeviceServiceImpl implements IDeviceService { } sync(device); }else { + device.setServerId(userSetting.getServerId()); if(!device.isOnLine()){ device.setOnLine(true); device.setCreateTime(now); @@ -164,12 +209,12 @@ public class DeviceServiceImpl implements IDeviceService { // TODO 如果设备下的通道级联到了其他平台,那么需要发送事件或者notify给上级平台 } // 上线添加订阅 - if (device.getSubscribeCycleForCatalog() > 0) { + if (device.getSubscribeCycleForCatalog() > 0 && !subscribeTaskRunner.containsKey(SubscribeTaskForCatalog.getKey(device))) { // 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 - addCatalogSubscribe(device); + addCatalogSubscribe(device, null); } - if (device.getSubscribeCycleForMobilePosition() > 0) { - addMobilePositionSubscribe(device); + if (device.getSubscribeCycleForMobilePosition() > 0 && !subscribeTaskRunner.containsKey(SubscribeTaskForMobilPosition.getKey(device))) { + addMobilePositionSubscribe(device, null); } if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 @@ -254,98 +299,173 @@ public class DeviceServiceImpl implements IDeviceService { } } - @Override - public boolean addCatalogSubscribe(Device device) { - if (device == null || device.getSubscribeCycleForCatalog() < 0) { - return false; + // 订阅丢失检查 + @Scheduled(fixedDelay = 10, timeUnit = TimeUnit.SECONDS) + public void lostCheck(){ + // 获取所有设备 + List deviceList = redisCatchStorage.getAllDevices(); + if (deviceList.isEmpty()) { + return; } - log.info("[添加目录订阅] 设备{}", device.getDeviceId()); - // 添加目录订阅 - CatalogSubscribeTask catalogSubscribeTask = new CatalogSubscribeTask(device, sipCommander, dynamicTask); - // 刷新订阅 - int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForCatalog(),30); - // 设置最小值为30 - dynamicTask.startCron(device.getDeviceId() + "catalog", catalogSubscribeTask, (subscribeCycleForCatalog -1) * 1000); + for (Device device : deviceList) { + if (device == null || !device.isOnLine() || !device.getServerId().equals(userSetting.getServerId())) { + continue; + } + if (device.getSubscribeCycleForCatalog() > 0 && !subscribeTaskRunner.containsKey(SubscribeTaskForCatalog.getKey(device))) { + log.debug("[订阅丢失] 目录订阅, 编号: {}, 重新发起订阅", device.getDeviceId()); + addCatalogSubscribe(device, null); + } + if (device.getSubscribeCycleForMobilePosition() > 0 && !subscribeTaskRunner.containsKey(SubscribeTaskForMobilPosition.getKey(device))) { + log.debug("[订阅丢失] 移动位置订阅, 编号: {}, 重新发起订阅", device.getDeviceId()); + addMobilePositionSubscribe(device, null); + } + } + } - catalogSubscribeTask.run(); - return true; + private void catalogSubscribeExpire(String deviceId, SipTransactionInfo transactionInfo) { + log.info("[目录订阅] 到期, 编号: {}", deviceId); + Device device = getDeviceByDeviceId(deviceId); + if (device == null) { + log.info("[目录订阅] 到期, 编号: {}, 设备不存在, 忽略", deviceId); + return; + } + if (device.getSubscribeCycleForCatalog() > 0) { + addCatalogSubscribe(device, transactionInfo); + } + } + + private void mobilPositionSubscribeExpire(String deviceId, SipTransactionInfo transactionInfo) { + log.info("[移动位置订阅] 到期, 编号: {}", deviceId); + Device device = getDeviceByDeviceId(deviceId); + if (device == null) { + log.info("[移动位置订阅] 到期, 编号: {}, 设备不存在, 忽略", deviceId); + return; + } + if (device.getSubscribeCycleForMobilePosition() > 0) { + addMobilePositionSubscribe(device, transactionInfo); + } } @Override - public boolean removeCatalogSubscribe(Device device, CommonCallback callback) { + public boolean addCatalogSubscribe(@NotNull Device device, SipTransactionInfo transactionInfo) { if (device == null || device.getSubscribeCycleForCatalog() < 0) { - if (callback != null) { - callback.run(false); - } return false; } - log.info("[移除目录订阅]: {}", device.getDeviceId()); - String taskKey = device.getDeviceId() + "catalog"; - if (device.isOnLine()) { - Runnable runnable = dynamicTask.get(taskKey); - if (runnable instanceof ISubscribeTask) { - ISubscribeTask subscribeTask = (ISubscribeTask) runnable; - subscribeTask.stop(callback); - }else { - log.info("[移除目录订阅]失败,未找到订阅任务 : {}", device.getDeviceId()); - if (callback != null) { - callback.run(false); + log.info("[添加目录订阅] 设备 {}", device.getDeviceId()); + try { + sipCommander.catalogSubscribe(device, transactionInfo, eventResult -> { + ResponseEvent event = (ResponseEvent) eventResult.event; + // 成功 + log.info("[目录订阅]成功: {}", device.getDeviceId()); + if (!subscribeTaskRunner.containsKey(SubscribeTaskForCatalog.getKey(device))) { + SIPResponse response = (SIPResponse) event.getResponse(); + SipTransactionInfo transactionInfoForResonse = new SipTransactionInfo(response); + SubscribeTask subscribeTask = SubscribeTaskForCatalog.getInstance(device, this::catalogSubscribeExpire, transactionInfoForResonse); + if (subscribeTask != null) { + subscribeTaskRunner.addSubscribe(subscribeTask); + } + }else { + subscribeTaskRunner.updateDelay(SubscribeTaskForCatalog.getKey(device), (device.getSubscribeCycleForCatalog() * 1000L - 500L) + System.currentTimeMillis()); } - } - }else { - log.info("[移除移动位置订阅]失败,设备已经离线 : {}", device.getDeviceId()); - if (callback != null) { - callback.run(false); - } + + },eventResult -> { + // 失败 + log.warn("[目录订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 目录订阅: {}", e.getMessage()); + return false; } - dynamicTask.stop(taskKey); return true; } @Override - public boolean addMobilePositionSubscribe(Device device) { - if (device == null || device.getSubscribeCycleForMobilePosition() < 0) { + public boolean removeCatalogSubscribe(@NotNull Device device, CommonCallback callback) { + log.info("[移除目录订阅]: {}", device.getDeviceId()); + String key = SubscribeTaskForCatalog.getKey(device); + if (subscribeTaskRunner.containsKey(key)) { + SipTransactionInfo transactionInfo = subscribeTaskRunner.getTransactionInfo(key); + if (transactionInfo == null) { + log.warn("[移除目录订阅] 未找到事务信息,{}", device.getDeviceId()); + } + try { + device.setSubscribeCycleForCatalog(0); + sipCommander.catalogSubscribe(device, transactionInfo, eventResult -> { + // 成功 + log.info("[取消目录订阅]成功: {}", device.getDeviceId()); + subscribeTaskRunner.removeSubscribe(SubscribeTaskForCatalog.getKey(device)); + if (callback != null) { + callback.run(true); + } + },eventResult -> { + // 失败 + log.warn("[取消目录订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); + }); + }catch (Exception e) { + // 失败 + log.warn("[取消目录订阅]失败: {}-{} ", device.getDeviceId(), e.getMessage()); + } + } + return true; + } + + @Override + public boolean addMobilePositionSubscribe(@NotNull Device device, SipTransactionInfo transactionInfo) { + log.info("[添加移动位置订阅] 设备 {}", device.getDeviceId()); + try { + sipCommander.mobilePositionSubscribe(device, transactionInfo, eventResult -> { + ResponseEvent event = (ResponseEvent) eventResult.event; + // 成功 + log.info("[移动位置订阅]成功: {}", device.getDeviceId()); + if (!subscribeTaskRunner.containsKey(SubscribeTaskForMobilPosition.getKey(device))) { + SIPResponse response = (SIPResponse) event.getResponse(); + SipTransactionInfo transactionInfoForResonse = new SipTransactionInfo(response); + SubscribeTask subscribeTask = SubscribeTaskForMobilPosition.getInstance(device, this::catalogSubscribeExpire, transactionInfoForResonse); + if (subscribeTask != null) { + subscribeTaskRunner.addSubscribe(subscribeTask); + } + }else { + subscribeTaskRunner.updateDelay(SubscribeTaskForMobilPosition.getKey(device), (device.getSubscribeCycleForCatalog() * 1000L - 500L) + System.currentTimeMillis()); + } + + },eventResult -> { + // 失败 + log.warn("[移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 移动位置订阅: {}", e.getMessage()); return false; } - log.info("[添加移动位置订阅] 设备{}", device.getDeviceId()); - // 添加目录订阅 - MobilePositionSubscribeTask mobilePositionSubscribeTask = new MobilePositionSubscribeTask(device, sipCommander, dynamicTask); - // 设置最小值为30 - int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForMobilePosition(),30); - // 刷新订阅 - dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, subscribeCycleForCatalog * 1000); - mobilePositionSubscribeTask.run(); return true; } @Override public boolean removeMobilePositionSubscribe(Device device, CommonCallback callback) { - if (device == null || device.getSubscribeCycleForCatalog() < 0) { - if (callback != null) { - callback.run(false); - } - return false; - } log.info("[移除移动位置订阅]: {}", device.getDeviceId()); - String taskKey = device.getDeviceId() + "mobile_position"; - if (device.isOnLine()) { - Runnable runnable = dynamicTask.get(taskKey); - if (runnable instanceof ISubscribeTask) { - ISubscribeTask subscribeTask = (ISubscribeTask) runnable; - subscribeTask.stop(callback); - }else { - log.info("[移除移动位置订阅]失败,未找到订阅任务 : {}", device.getDeviceId()); - if (callback != null) { - callback.run(false); - } + String key = SubscribeTaskForMobilPosition.getKey(device); + if (subscribeTaskRunner.containsKey(key)) { + SipTransactionInfo transactionInfo = subscribeTaskRunner.getTransactionInfo(key); + if (transactionInfo == null) { + log.warn("[移除移动位置订阅] 未找到事务信息,{}", device.getDeviceId()); } - }else { - log.info("[移除移动位置订阅]失败,设备已经离线 : {}", device.getDeviceId()); - if (callback != null) { - callback.run(false); + try { + device.setSubscribeCycleForMobilePosition(0); + sipCommander.mobilePositionSubscribe(device, transactionInfo, eventResult -> { + // 成功 + log.info("[取消移动位置订阅]成功: {}", device.getDeviceId()); + subscribeTaskRunner.removeSubscribe(SubscribeTaskForMobilPosition.getKey(device)); + if (callback != null) { + callback.run(true); + } + },eventResult -> { + // 失败 + log.warn("[取消移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); + }); + }catch (Exception e) { + // 失败 + log.warn("[取消移动位置订阅]失败: {}-{} ", device.getDeviceId(), e.getMessage()); } } - dynamicTask.stop(taskKey); return true; } @@ -499,10 +619,20 @@ public class DeviceServiceImpl implements IDeviceService { public boolean delete(String deviceId) { Device device = getDeviceByDeviceIdFromDb(deviceId); Assert.notNull(device, "未找到设备"); + if (subscribeTaskRunner.containsKey(SubscribeTaskForCatalog.getKey(device))) { + removeCatalogSubscribe(device, null); + } + if (subscribeTaskRunner.containsKey(SubscribeTaskForMobilPosition.getKey(device))) { + removeMobilePositionSubscribe(device, null); + } + // 停止状态检测 + String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId(); + dynamicTask.stop(registerExpireTaskKey); platformChannelMapper.delChannelForDeviceId(deviceId); deviceChannelMapper.cleanChannelsByDeviceId(device.getId()); deviceMapper.del(deviceId); redisCatchStorage.removeDevice(deviceId); + inviteStreamService.clearInviteInfo(deviceId); return true; } @@ -562,20 +692,17 @@ public class DeviceServiceImpl implements IDeviceService { // 订阅周期不同,则先取消 removeCatalogSubscribe(device, result->{ device.setSubscribeCycleForCatalog(cycle); + updateDevice(device); if (cycle > 0) { // 开启订阅 - addCatalogSubscribe(device); + addCatalogSubscribe(device, null); } - // 因为是异步执行,需要在这里更新下数据 - deviceMapper.updateSubscribeCatalog(device); - redisCatchStorage.updateDevice(device); }); }else { // 开启订阅 device.setSubscribeCycleForCatalog(cycle); - addCatalogSubscribe(device); - deviceMapper.updateSubscribeCatalog(device); - redisCatchStorage.updateDevice(device); + updateDevice(device); + addCatalogSubscribe(device, null); } } @@ -583,6 +710,7 @@ public class DeviceServiceImpl implements IDeviceService { public void subscribeMobilePosition(int id, int cycle, int interval) { Device device = deviceMapper.query(id); Assert.notNull(device, "未找到设备"); + if (device.getSubscribeCycleForMobilePosition() == cycle) { return; } @@ -598,21 +726,16 @@ public class DeviceServiceImpl implements IDeviceService { device.setSubscribeCycleForMobilePosition(cycle); device.setMobilePositionSubmissionInterval(interval); if (cycle > 0) { - addMobilePositionSubscribe(device); + addMobilePositionSubscribe(device, null); } - // 因为是异步执行,需要在这里更新下数据 - deviceMapper.updateSubscribeMobilePosition(device); - redisCatchStorage.updateDevice(device); }); }else { // 订阅未开启 device.setSubscribeCycleForMobilePosition(cycle); device.setMobilePositionSubmissionInterval(interval); + updateDevice(device); // 开启订阅 - addMobilePositionSubscribe(device); - // 因为是异步执行,需要在这里更新下数据 - deviceMapper.updateSubscribeMobilePosition(device); - redisCatchStorage.updateDevice(device); + addMobilePositionSubscribe(device, null); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelPlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelPlayServiceImpl.java index 2e5b8e234..71c4b0b0a 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelPlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelPlayServiceImpl.java @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.service.impl; import com.genersoft.iot.vmp.common.InviteSessionType; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.exception.ServiceException; import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.common.enums.ChannelDataType; @@ -145,6 +146,9 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { deviceChannelPlayService.play(channel, record, callback); } catch (PlayException e) { callback.run(e.getCode(), e.getMsg(), null); + } catch (ControllerException e) { + log.error("[点播失败] {}({}), {}", channel.getGbName(), channel.getGbDeviceId(), e.getMsg()); + callback.run(Response.BUSY_HERE, "busy here", null); } catch (Exception e) { log.error("[点播失败] {}({})", channel.getGbName(), channel.getGbDeviceId(), e); callback.run(Response.BUSY_HERE, "busy here", null); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java index a1c493ba2..faeecf4ba 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java @@ -13,6 +13,7 @@ import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService; import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; import com.genersoft.iot.vmp.gb28181.service.IPlatformChannelService; import com.genersoft.iot.vmp.service.bean.ErrorCallback; +import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.streamPush.bean.StreamPush; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; @@ -159,30 +160,26 @@ public class GbChannelServiceImpl implements IGbChannelService { log.warn("[多个通道离线] 通道数量为0,更新失败"); return 0; } - List onlineChannelList = commonGBChannelMapper.queryInListByStatus(commonGBChannelList, "ON"); - if (onlineChannelList.isEmpty()) { - log.info("[多个通道离线] 更新失败, 参数内通道已经离线, 无需更新"); - return 0; - } + log.info("[通道离线] 共 {} 个", commonGBChannelList.size()); int limitCount = 1000; int result = 0; - if (onlineChannelList.size() > limitCount) { - for (int i = 0; i < onlineChannelList.size(); i += limitCount) { + if (commonGBChannelList.size() > limitCount) { + for (int i = 0; i < commonGBChannelList.size(); i += limitCount) { int toIndex = i + limitCount; - if (i + limitCount > onlineChannelList.size()) { - toIndex = onlineChannelList.size(); + if (i + limitCount > commonGBChannelList.size()) { + toIndex = commonGBChannelList.size(); } - result += commonGBChannelMapper.updateStatusForListById(onlineChannelList.subList(i, toIndex), "OFF"); + result += commonGBChannelMapper.updateStatusForListById(commonGBChannelList.subList(i, toIndex), "OFF"); } } else { - result += commonGBChannelMapper.updateStatusForListById(onlineChannelList, "OFF"); + result += commonGBChannelMapper.updateStatusForListById(commonGBChannelList, "OFF"); } if (result > 0) { try { // 发送catalog - eventPublisher.catalogEventPublish(null, onlineChannelList, CatalogEvent.OFF); + eventPublisher.catalogEventPublish(null, commonGBChannelList, CatalogEvent.OFF); } catch (Exception e) { - log.warn("[多个通道离线] 发送失败,数量:{}", onlineChannelList.size(), e); + log.warn("[多个通道离线] 发送失败,数量:{}", commonGBChannelList.size(), e); } } return result; @@ -213,32 +210,25 @@ public class GbChannelServiceImpl implements IGbChannelService { log.warn("[多个通道上线] 通道数量为0,更新失败"); return 0; } - List offlineChannelList = commonGBChannelMapper.queryInListByStatus(commonGBChannelList, "OFF"); - if (offlineChannelList.isEmpty()) { - log.warn("[多个通道上线] 更新失败, 参数内通道已经上线"); - return 0; - } // 批量更新 int limitCount = 1000; int result = 0; - if (offlineChannelList.size() > limitCount) { - for (int i = 0; i < offlineChannelList.size(); i += limitCount) { + if (commonGBChannelList.size() > limitCount) { + for (int i = 0; i < commonGBChannelList.size(); i += limitCount) { int toIndex = i + limitCount; - if (i + limitCount > offlineChannelList.size()) { - toIndex = offlineChannelList.size(); + if (i + limitCount > commonGBChannelList.size()) { + toIndex = commonGBChannelList.size(); } - result += commonGBChannelMapper.updateStatusForListById(offlineChannelList.subList(i, toIndex), "ON"); + result += commonGBChannelMapper.updateStatusForListById(commonGBChannelList.subList(i, toIndex), "ON"); } } else { - result += commonGBChannelMapper.updateStatusForListById(offlineChannelList, "ON"); + result += commonGBChannelMapper.updateStatusForListById(commonGBChannelList, "ON"); } - if (result > 0) { - try { - // 发送catalog - eventPublisher.catalogEventPublish(null, offlineChannelList, CatalogEvent.ON); - } catch (Exception e) { - log.warn("[多个通道上线] 发送失败,数量:{}", offlineChannelList.size(), e); - } + try { + // 发送catalog + eventPublisher.catalogEventPublish(null, commonGBChannelList, CatalogEvent.ON); + } catch (Exception e) { + log.warn("[多个通道上线] 发送失败,数量:{}", commonGBChannelList.size(), e); } return result; @@ -715,11 +705,6 @@ public class GbChannelServiceImpl implements IGbChannelService { return commonGBChannelMapper.queryListByStreamPushList(ChannelDataType.STREAM_PUSH.value, streamPushList); } - @Override - public void updateGpsByDeviceIdForStreamPush(List channels) { - commonGBChannelMapper.updateGpsByDeviceIdForStreamPush(ChannelDataType.STREAM_PUSH.value, channels); - } - @Override public PageInfo queryList(int page, int count, String query, Boolean online, Boolean hasRecordPlan, Integer channelType) { PageHelper.startPage(page, count); @@ -762,4 +747,47 @@ public class GbChannelServiceImpl implements IGbChannelService { List all = commonGBChannelMapper.queryListByCivilCodeForUnusual(query, online, channelType); return new PageInfo<>(all); } + + @Override + public void clearChannelCivilCode(Boolean all, List channelIds) { + + List channelIdsForClear; + if (all != null && all) { + channelIdsForClear = commonGBChannelMapper.queryAllForUnusualCivilCode(); + }else { + channelIdsForClear = channelIds; + } + commonGBChannelMapper.removeCivilCodeByChannelIds(channelIdsForClear); + } + + @Override + public PageInfo queryListByParentForUnusual(int page, int count, String query, Boolean online, Integer channelType) { + PageHelper.startPage(page, count); + if (query != null) { + query = query.replaceAll("/", "//") + .replaceAll("%", "/%") + .replaceAll("_", "/_"); + } + List all = commonGBChannelMapper.queryListByParentForUnusual(query, online, channelType); + return new PageInfo<>(all); + } + + @Override + public void clearChannelParent(Boolean all, List channelIds) { + List channelIdsForClear; + if (all != null && all) { + channelIdsForClear = commonGBChannelMapper.queryAllForUnusualParent(); + }else { + channelIdsForClear = channelIds; + } + commonGBChannelMapper.removeParentIdByChannelIds(channelIdsForClear); + } + + @Override + public void updateGPSFromGPSMsgInfo(List gpsMsgInfoList) { + if (gpsMsgInfoList == null || gpsMsgInfoList.isEmpty()) { + return; + } + commonGBChannelMapper.updateGpsByDeviceId(gpsMsgInfoList); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformChannelServiceImpl.java index ff11f2ef7..f4bd244a2 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformChannelServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformChannelServiceImpl.java @@ -601,4 +601,12 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { public List queryChannelByPlatformIdAndChannelIds(Integer platformId, List channelIds) { return platformChannelMapper.queryShare(platformId, channelIds); } + + @Override + public List queryByPlatformBySharChannelId(String channelDeviceId) { + CommonGBChannel commonGBChannel = commonGBChannelMapper.queryByDeviceId(channelDeviceId); + ArrayList ids = new ArrayList<>(); + ids.add(commonGBChannel.getGbId()); + return platformChannelMapper.queryPlatFormListByChannelList(ids); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java index f76c0dc81..085b6421c 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java @@ -1,6 +1,5 @@ package com.genersoft.iot.vmp.gb28181.service.impl; -import com.genersoft.iot.vmp.common.InviteInfo; import com.genersoft.iot.vmp.common.*; import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.SipConfig; @@ -15,6 +14,10 @@ import com.genersoft.iot.vmp.gb28181.service.IInviteStreamService; import com.genersoft.iot.vmp.gb28181.service.IPlatformService; import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager; +import com.genersoft.iot.vmp.gb28181.task.platformStatus.PlatformKeepaliveTask; +import com.genersoft.iot.vmp.gb28181.task.platformStatus.PlatformRegisterTask; +import com.genersoft.iot.vmp.gb28181.task.platformStatus.PlatformRegisterTaskInfo; +import com.genersoft.iot.vmp.gb28181.task.platformStatus.PlatformStatusTaskRunner; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; import com.genersoft.iot.vmp.gb28181.utils.SipUtils; import com.genersoft.iot.vmp.media.bean.MediaInfo; @@ -28,13 +31,14 @@ import com.genersoft.iot.vmp.service.ISendRtpServerService; import com.genersoft.iot.vmp.service.bean.*; import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import com.genersoft.iot.vmp.utils.DateUtil; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import gov.nist.javax.sip.message.SIPResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; import org.springframework.context.event.EventListener; +import org.springframework.core.annotation.Order; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @@ -56,12 +60,8 @@ import java.util.concurrent.TimeUnit; */ @Slf4j @Service -public class PlatformServiceImpl implements IPlatformService { - - private final static String REGISTER_KEY_PREFIX = "platform_register_"; - - private final static String REGISTER_FAIL_AGAIN_KEY_PREFIX = "platform_register_fail_again_"; - private final static String KEEPALIVE_KEY_PREFIX = "platform_keepalive_"; +@Order(value=15) +public class PlatformServiceImpl implements IPlatformService, CommandLineRunner { @Autowired private PlatformMapper platformMapper; @@ -69,7 +69,6 @@ public class PlatformServiceImpl implements IPlatformService { @Autowired private IRedisCatchStorage redisCatchStorage; - @Autowired private SSRCFactory ssrcFactory; @@ -109,6 +108,74 @@ public class PlatformServiceImpl implements IPlatformService { @Autowired private ISendRtpServerService sendRtpServerService; + @Autowired + private PlatformStatusTaskRunner statusTaskRunner; + + @Override + public void run(String... args) throws Exception { + // 启动时 如果存在未过期的注册平台,则发送注销 + List registerTaskInfoList = statusTaskRunner.getAllRegisterTaskInfo(); + if (registerTaskInfoList.isEmpty()) { + return; + } + for (PlatformRegisterTaskInfo taskInfo : registerTaskInfoList) { + log.info("[国标级联] 启动服务是发现平台注册仍在有效期,注销: {}", taskInfo.getPlatformServerId()); + Platform platform = queryPlatformByServerGBId(taskInfo.getPlatformServerId()); + if (platform == null) { + statusTaskRunner.removeRegisterTask(taskInfo.getPlatformServerId()); + continue; + } + sendUnRegister(platform, taskInfo.getSipTransactionInfo()); + } + // 启动时所有平台默认离线 + platformMapper.offlineAll(userSetting.getServerId()); + } + @Scheduled(fixedDelay = 20, timeUnit = TimeUnit.SECONDS) //每3秒执行一次 + public void statusLostCheck(){ + // 每隔20秒检测,是否存在启用但是未注册的平台,存在则发起注册 + // 获取所有在线并且启用的平台 + List platformList = platformMapper.queryServerIdsWithEnableAndServer(userSetting.getServerId()); + if (platformList.isEmpty()) { + return; + } + for (Platform platform : platformList) { + if (statusTaskRunner.containsRegister(platform.getServerGBId()) && statusTaskRunner.containsKeepAlive(platform.getServerGBId())) { + continue; + } + if (statusTaskRunner.containsRegister(platform.getServerGBId())) { + SipTransactionInfo transactionInfo = statusTaskRunner.getRegisterTransactionInfo(platform.getServerGBId()); + // 注销后出发平台离线, 如果是启用的平台,那么下次丢失检测会检测到并重新注册上线 + sendUnRegister(platform, transactionInfo); + }else { + statusTaskRunner.removeKeepAliveTask(platform.getServerGBId()); + sendRegister(platform, null); + } + } + } + + private void sendRegister(Platform platform, SipTransactionInfo sipTransactionInfo) { + try { + commanderForPlatform.register(platform, sipTransactionInfo, eventResult -> { + log.info("[国标级联] {}({}),注册失败", platform.getName(), platform.getServerGBId()); + offline(platform); + }, null); + } catch (InvalidArgumentException | ParseException | SipException e) { + log.error("[命令发送失败] 国标级联: {}", e.getMessage()); + } + } + + private void sendUnRegister(Platform platform, SipTransactionInfo sipTransactionInfo) { + statusTaskRunner.removeRegisterTask(platform.getServerGBId()); + statusTaskRunner.removeKeepAliveTask(platform.getServerGBId()); + try { + commanderForPlatform.unregister(platform, sipTransactionInfo, null, eventResult -> { + log.info("[国标级联] 注销成功, 平台:{}", platform.getServerGBId()); + }); + } catch (InvalidArgumentException | ParseException | SipException e) { + log.error("[命令发送失败] 国标级联: {}", e.getMessage()); + } + } + // 定时监听国标级联所进行的WVP服务是否正常, 如果异常则选择新的wvp执行 @Scheduled(fixedDelay = 2, timeUnit = TimeUnit.SECONDS) //每3秒执行一次 public void execute(){ @@ -127,6 +194,7 @@ public class PlatformServiceImpl implements IPlatformService { return; } log.info("[集群] 检测到 {} 已离线", serverId); + redisCatchStorage.removeOfflineWVPInfo(serverId); String chooseServerId = redisCatchStorage.chooseOneServer(serverId); if (!userSetting.getServerId().equals(chooseServerId)){ return; @@ -139,20 +207,26 @@ public class PlatformServiceImpl implements IPlatformService { platform.setAddress(getIpWithSameNetwork(platform.getAddress())); platform.setServerId(userSetting.getServerId()); platformMapper.update(platform); - // 更新redis - redisCatchStorage.delPlatformCatchInfo(platform.getServerGBId()); - PlatformCatch platformCatch = new PlatformCatch(); - platformCatch.setPlatform(platform); - platformCatch.setId(platform.getServerGBId()); - redisCatchStorage.updatePlatformCatchInfo(platformCatch); - // 开始注册 - // 注册成功时由程序直接调用了online方法 - try { - commanderForPlatform.register(platform, eventResult -> { - log.info("[国标级联] {}({}),添加向上级注册失败,请确定上级平台可用时重新保存", platform.getName(), platform.getServerGBId()); - }, null); - } catch (InvalidArgumentException | ParseException | SipException e) { - log.error("[命令发送失败] 国标级联: {}", e.getMessage()); + // 检查就平台是否注册到期,没有则注销,由本平台重新注册 + List taskInfoList = statusTaskRunner.getRegisterTransactionInfoByServerId(serverId); + boolean needUnregister = false; + SipTransactionInfo sipTransactionInfo = null; + if (!taskInfoList.isEmpty()) { + for (PlatformRegisterTaskInfo taskInfo : taskInfoList) { + if (taskInfo.getPlatformServerId().equals(platform.getServerGBId()) + && taskInfo.getSipTransactionInfo() != null) { + needUnregister = true; + sipTransactionInfo = taskInfo.getSipTransactionInfo(); + break; + } + } + } + if (needUnregister) { + sendUnRegister(platform, sipTransactionInfo); + }else { + // 开始注册 + // 注册成功时由程序直接调用了online方法 + sendRegister(platform, null); } }); }); @@ -265,25 +339,17 @@ public class PlatformServiceImpl implements IPlatformService { } platform.setServerId(userSetting.getServerId()); int result = platformMapper.add(platform); - // 添加缓存 - PlatformCatch platformCatch = new PlatformCatch(); - platformCatch.setPlatform(platform); - platformCatch.setId(platform.getServerGBId()); - redisCatchStorage.updatePlatformCatchInfo(platformCatch); + if (platform.isEnable()) { // 保存时启用就发送注册 // 注册成功时由程序直接调用了online方法 - try { - commanderForPlatform.register(platform, eventResult -> { - log.info("[国标级联] {}({}),添加向上级注册失败,请确定上级平台可用时重新保存", platform.getName(), platform.getServerGBId()); - }, null); - } catch (InvalidArgumentException | ParseException | SipException e) { - log.error("[命令发送失败] 国标级联: {}", e.getMessage()); - } + sendRegister(platform, null); } return result > 0; } + + @Override public boolean update(Platform platform) { Assert.isTrue(platform.getId() > 0, "ID必须存在"); @@ -294,52 +360,15 @@ public class PlatformServiceImpl implements IPlatformService { if (!userSetting.getServerId().equals(platformInDb.getServerId())) { return redisRpcService.updatePlatform(platformInDb.getServerId(), platform); } - - PlatformCatch platformCatchOld = redisCatchStorage.queryPlatformCatchInfo(platformInDb.getServerGBId()); - platform.setUpdateTime(DateUtil.getNow()); - - // 停止心跳定时 - final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + platformInDb.getServerGBId(); - dynamicTask.stop(keepaliveTaskKey); - // 停止注册定时 - final String registerTaskKey = REGISTER_KEY_PREFIX + platformInDb.getServerGBId(); - dynamicTask.stop(registerTaskKey); - // 注销旧的 - try { - if (platformInDb.isStatus() && platformCatchOld != null) { - log.info("保存平台{}时发现旧平台在线,发送注销命令", platformInDb.getServerGBId()); - commanderForPlatform.unregister(platformInDb, platformCatchOld.getSipTransactionInfo(), null, eventResult -> { - log.info("[国标级联] 注销成功, 平台:{}", platformInDb.getServerGBId()); - }); - } - } catch (InvalidArgumentException | ParseException | SipException e) { - log.error("[命令发送失败] 国标级联 注销: {}", e.getMessage()); - } - // 更新数据库 if (platform.getCatalogGroup() == 0) { platform.setCatalogGroup(1); } - platformMapper.update(platform); - // 更新redis - redisCatchStorage.delPlatformCatchInfo(platformInDb.getServerGBId()); - PlatformCatch platformCatch = new PlatformCatch(); - platformCatch.setPlatform(platform); - platformCatch.setId(platform.getServerGBId()); - redisCatchStorage.updatePlatformCatchInfo(platformCatch); - // 注册 - if (platform.isEnable()) { - // 保存时启用就发送注册 - // 注册成功时由程序直接调用了online方法 - try { - log.info("[国标级联] 平台注册 {}", platform.getDeviceGBId()); - commanderForPlatform.register(platform, eventResult -> { - log.info("[国标级联] {},添加向上级注册失败,请确定上级平台可用时重新保存", platform.getServerGBId()); - }, null); - } catch (InvalidArgumentException | ParseException | SipException e) { - log.error("[命令发送失败] 国标级联: {}", e.getMessage()); - } + if (statusTaskRunner.containsRegister(platformInDb.getServerGBId())) { + SipTransactionInfo transactionInfo = statusTaskRunner.getRegisterTransactionInfo(platformInDb.getServerGBId()); + // 注销后出发平台离线, 如果是启用的平台,那么下次丢失检测会检测到并重新注册上线 + sendUnRegister(platformInDb, transactionInfo); } return false; @@ -348,79 +377,21 @@ public class PlatformServiceImpl implements IPlatformService { @Override public void online(Platform platform, SipTransactionInfo sipTransactionInfo) { log.info("[国标级联]:{}, 平台上线", platform.getServerGBId()); - final String registerFailAgainTaskKey = REGISTER_FAIL_AGAIN_KEY_PREFIX + platform.getServerGBId(); - dynamicTask.stop(registerFailAgainTaskKey); + PlatformRegisterTask registerTask = new PlatformRegisterTask(platform.getServerGBId(), platform.getExpires() * 1000L - 500L, + sipTransactionInfo, (platformServerGbId) -> { + this.registerExpire(platformServerGbId, sipTransactionInfo); + }); + statusTaskRunner.addRegisterTask(registerTask); - platformMapper.updateStatus(platform.getServerGBId(), true); - PlatformCatch platformCatch = redisCatchStorage.queryPlatformCatchInfo(platform.getServerGBId()); - if (platformCatch == null) { - platformCatch = new PlatformCatch(); - platformCatch.setPlatform(platform); - platformCatch.setId(platform.getServerGBId()); - platform.setStatus(true); - platformCatch.setPlatform(platform); - } + PlatformKeepaliveTask keepaliveTask = new PlatformKeepaliveTask(platform.getServerGBId(), platform.getKeepTimeout() * 1000L, + this::keepaliveExpire); + statusTaskRunner.addKeepAliveTask(keepaliveTask); + platformMapper.updateStatus(platform.getId(), true, userSetting.getServerId()); - platformCatch.getPlatform().setStatus(true); - platformCatch.setSipTransactionInfo(sipTransactionInfo); - redisCatchStorage.updatePlatformCatchInfo(platformCatch); - - final String registerTaskKey = REGISTER_KEY_PREFIX + platform.getServerGBId(); - if (!dynamicTask.isAlive(registerTaskKey)) { - log.info("[国标级联]:{}, 添加定时注册任务", platform.getServerGBId()); - // 添加注册任务 - dynamicTask.startCron(registerTaskKey, - // 注册失败(注册成功时由程序直接调用了online方法) - ()-> registerTask(platform, sipTransactionInfo), - platform.getExpires() * 1000); - } - - - final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + platform.getServerGBId(); - if (!dynamicTask.contains(keepaliveTaskKey)) { - log.info("[国标级联]:{}, 添加定时心跳任务", platform.getServerGBId()); - // 添加心跳任务 - dynamicTask.startCron(keepaliveTaskKey, - ()-> { - try { - commanderForPlatform.keepalive(platform, eventResult -> { - // 心跳失败 - if (eventResult.type != SipSubscribe.EventResultType.timeout) { - log.warn("[国标级联]发送心跳收到错误,code: {}, msg: {}", eventResult.statusCode, eventResult.msg); - } - // 心跳失败 - PlatformCatch platformCatchForNow = redisCatchStorage.queryPlatformCatchInfo(platform.getServerGBId()); - // 此时是第三次心跳超时, 平台离线 - if (platformCatchForNow.getKeepAliveReply() == 2) { - // 设置平台离线,并重新注册 - log.info("[国标级联] 三次心跳失败, 平台{}({})离线", platform.getName(), platform.getServerGBId()); - offline(platform, false); - }else { - platformCatchForNow.setKeepAliveReply(platformCatchForNow.getKeepAliveReply() + 1); - redisCatchStorage.updatePlatformCatchInfo(platformCatchForNow); - } - - }, eventResult -> { - // 心跳成功 - // 清空之前的心跳超时计数 - PlatformCatch platformCatchForNow = redisCatchStorage.queryPlatformCatchInfo(platform.getServerGBId()); - if (platformCatchForNow != null && platformCatchForNow.getKeepAliveReply() > 0) { - platformCatchForNow.setKeepAliveReply(0); - redisCatchStorage.updatePlatformCatchInfo(platformCatchForNow); - } - log.info("[国标级联] 发送心跳,平台{}({}), code: {}, msg: {}", platform.getName(), platform.getServerGBId(), eventResult.statusCode, eventResult.msg); - }); - } catch (SipException | InvalidArgumentException | ParseException e) { - log.error("[命令发送失败] 国标级联 发送心跳: {}", e.getMessage()); - } - }, - (platform.getKeepTimeout())*1000); - } if (platform.getAutoPushChannel() != null && platform.getAutoPushChannel()) { if (subscribeHolder.getCatalogSubscribe(platform.getServerGBId()) == null) { log.info("[国标级联]:{}, 添加自动通道推送模拟订阅信息", platform.getServerGBId()); addSimulatedSubscribeInfo(platform); - } }else { SubscribeInfo catalogSubscribe = subscribeHolder.getCatalogSubscribe(platform.getServerGBId()); @@ -430,6 +401,65 @@ public class PlatformServiceImpl implements IPlatformService { } } + /** + * 注册到期处理 + */ + private void registerExpire(String platformServerId, SipTransactionInfo transactionInfo) { + log.info("[国标级联] 注册到期, 上级平台编号: {}", platformServerId); + Platform platform = queryPlatformByServerGBId(platformServerId); + if (platform == null || !platform.isEnable()) { + log.info("[国标级联] 注册到期, 上级平台编号: {}, 平台不存在或者未启用, 忽略", platformServerId); + return; + } + sendRegister(platform, transactionInfo); + } + + private void keepaliveExpire(String platformServerId, int failCount) { + log.info("[国标级联] 心跳到期, 上级平台编号: {}", platformServerId); + Platform platform = queryPlatformByServerGBId(platformServerId); + if (platform == null || !platform.isEnable()) { + log.info("[国标级联] 心跳到期, 上级平台编号: {}, 平台不存在或者未启用, 忽略", platformServerId); + return; + } + try { + commanderForPlatform.keepalive(platform, eventResult -> { + // 心跳失败 + if (eventResult.type != SipSubscribe.EventResultType.timeout) { + log.warn("[国标级联] 发送心跳收到错误,code: {}, msg: {}", eventResult.statusCode, eventResult.msg); + } + + // 心跳超时失败 + if (failCount < 2) { + log.info("[国标级联] 心跳发送超时, 平台服务编号: {}", platformServerId); + PlatformKeepaliveTask keepaliveTask = new PlatformKeepaliveTask(platform.getServerGBId(), platform.getKeepTimeout() * 1000L, + this::keepaliveExpire); + keepaliveTask.setFailCount(failCount + 1); + statusTaskRunner.addKeepAliveTask(keepaliveTask); + }else { + // 心跳超时三次, 不再发送心跳, 平台离线 + log.info("[国标级联] 心跳发送超时三次,平台离线, 平台服务编号: {}", platformServerId); + offline(platform); + } + }, eventResult -> { + PlatformKeepaliveTask keepaliveTask = new PlatformKeepaliveTask(platform.getServerGBId(), platform.getKeepTimeout() * 1000L, + this::keepaliveExpire); + statusTaskRunner.addKeepAliveTask(keepaliveTask); + }); + } catch (SipException | InvalidArgumentException | ParseException e) { + log.error("[命令发送失败] 国标级联 发送心跳: {}", e.getMessage()); + if (failCount < 2) { + PlatformKeepaliveTask keepaliveTask = new PlatformKeepaliveTask(platform.getServerGBId(), platform.getKeepTimeout() * 1000L, + this::keepaliveExpire); + keepaliveTask.setFailCount(failCount + 1); + statusTaskRunner.addKeepAliveTask(keepaliveTask); + }else { + // 心跳超时三次, 不再发送心跳, 平台离线 + log.info("[国标级联] 心跳发送失败三次,平台离线, 平台服务编号: {}", platformServerId); + offline(platform); + } + } + } + @Override public void addSimulatedSubscribeInfo(Platform platform) { // 自动添加一条模拟的订阅信息 @@ -437,87 +467,25 @@ public class PlatformServiceImpl implements IPlatformService { SubscribeInfo.buildSimulated(platform.getServerGBId(), platform.getServerIp())); } - private void registerTask(Platform platform, SipTransactionInfo sipTransactionInfo){ - try { - // 不在同一个会话中续订则每次全新注册 - if (!userSetting.isRegisterKeepIntDialog()) { - sipTransactionInfo = null; - } - - if (sipTransactionInfo == null) { - log.info("[国标级联] 平台:{}注册即将到期,开始重新注册", platform.getServerGBId()); - }else { - log.info("[国标级联] 平台:{}注册即将到期,开始续订", platform.getServerGBId()); - } - - commanderForPlatform.register(platform, sipTransactionInfo, eventResult -> { - log.info("[国标级联] 平台:{}注册失败,{}:{}", platform.getServerGBId(), - eventResult.statusCode, eventResult.msg); - if (platform.isStatus()) { - offline(platform, false); - } - }, null); - } catch (Exception e) { - log.error("[命令发送失败] 国标级联定时注册: {}", e.getMessage()); - } - } - @Override - public void offline(Platform platform, boolean stopRegister) { + public void offline(Platform platform) { log.info("[平台离线]:{}({})", platform.getName(), platform.getServerGBId()); - PlatformCatch platformCatch = redisCatchStorage.queryPlatformCatchInfo(platform.getServerGBId()); - platformCatch.setKeepAliveReply(0); - platformCatch.setRegisterAliveReply(0); - Platform catchPlatform = platformCatch.getPlatform(); - catchPlatform.setStatus(false); - platformCatch.setPlatform(catchPlatform); - redisCatchStorage.updatePlatformCatchInfo(platformCatch); - platformMapper.updateStatus(platform.getServerGBId(), false); + statusTaskRunner.removeRegisterTask(platform.getServerGBId()); + statusTaskRunner.removeKeepAliveTask(platform.getServerGBId()); + + subscribeHolder.removeCatalogSubscribe(platform.getServerGBId()); + subscribeHolder.removeMobilePositionSubscribe(platform.getServerGBId()); + + platformMapper.updateStatus(platform.getId(), false, userSetting.getServerId()); // 停止所有推流 log.info("[平台离线] {}({}), 停止所有推流", platform.getName(), platform.getServerGBId()); stopAllPush(platform.getServerGBId()); - - // 清除注册定时 - log.info("[平台离线] {}({}), 停止定时注册任务", platform.getName(), platform.getServerGBId()); - final String registerTaskKey = REGISTER_KEY_PREFIX + platform.getServerGBId(); - if (dynamicTask.contains(registerTaskKey)) { - dynamicTask.stop(registerTaskKey); - } - // 清除心跳定时 - log.info("[平台离线] {}({}), 停止定时发送心跳任务", platform.getName(), platform.getServerGBId()); - final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + platform.getServerGBId(); - if (dynamicTask.contains(keepaliveTaskKey)) { - // 清除心跳任务 - dynamicTask.stop(keepaliveTaskKey); - } - // 停止订阅回复 - SubscribeInfo catalogSubscribe = subscribeHolder.getCatalogSubscribe(platform.getServerGBId()); - if (catalogSubscribe != null) { - if (catalogSubscribe.getExpires() > 0) { - log.info("[平台离线] {}({}), 停止目录订阅回复", platform.getName(), platform.getServerGBId()); - subscribeHolder.removeCatalogSubscribe(platform.getServerGBId()); - } - } - - log.info("[平台离线] {}({}), 停止移动位置订阅回复", platform.getName(), platform.getServerGBId()); - subscribeHolder.removeMobilePositionSubscribe(platform.getServerGBId()); - // 发起定时自动重新注册 - if (!stopRegister) { - // 设置为60秒自动尝试重新注册 - final String registerFailAgainTaskKey = REGISTER_FAIL_AGAIN_KEY_PREFIX + platform.getServerGBId(); - Platform platformInDb = platformMapper.query(platform.getId()); - if (platformInDb.isEnable()) { - dynamicTask.startCron(registerFailAgainTaskKey, - ()-> registerTask(platformInDb, null), - userSetting.getRegisterAgainAfterTime() * 1000); - } - } } private void stopAllPush(String platformId) { List sendRtpItems = sendRtpServerService.queryForPlatform(platformId); - if (sendRtpItems != null && sendRtpItems.size() > 0) { + if (sendRtpItems != null && !sendRtpItems.isEmpty()) { for (SendRtpInfo sendRtpItem : sendRtpItems) { ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc()); sendRtpServerService.delete(sendRtpItem); @@ -527,23 +495,6 @@ public class PlatformServiceImpl implements IPlatformService { } } - @Override - public void login(Platform platform) { - final String registerTaskKey = REGISTER_KEY_PREFIX + platform.getServerGBId(); - try { - commanderForPlatform.register(platform, eventResult1 -> { - log.info("[国标级联] {},开始定时发起注册,间隔为1分钟", platform.getServerGBId()); - // 添加注册任务 - dynamicTask.startCron(registerTaskKey, - // 注册失败(注册成功时由程序直接调用了online方法) - ()-> log.info("[国标级联] {}({}),平台离线后持续发起注册,失败", platform.getName(), platform.getServerGBId()), - 60*1000); - }, null); - } catch (InvalidArgumentException | ParseException | SipException e) { - log.error("[命令发送失败] 国标级联注册: {}", e.getMessage()); - } - } - @Override public void sendNotifyMobilePosition(String platformId) { Platform platform = platformMapper.getParentPlatByServerGBId(platformId); @@ -559,12 +510,25 @@ public class PlatformServiceImpl implements IPlatformService { } for (CommonGBChannel channel : channelList) { GPSMsgInfo gpsMsgInfo = redisCatchStorage.getGpsMsgInfo(channel.getGbDeviceId()); + + // 无最新位置则发送当前位置 + if (gpsMsgInfo != null && (gpsMsgInfo.getLng() == 0 && gpsMsgInfo.getLat() == 0)) { + gpsMsgInfo = null; + } + + if (gpsMsgInfo == null && !userSetting.isSendPositionOnDemand()){ + gpsMsgInfo = new GPSMsgInfo(); + gpsMsgInfo.setId(channel.getGbDeviceId()); + gpsMsgInfo.setLng(channel.getGbLongitude()); + gpsMsgInfo.setLat(channel.getGbLatitude()); + gpsMsgInfo.setAltitude(channel.getGpsAltitude()); + gpsMsgInfo.setSpeed(channel.getGpsSpeed()); + gpsMsgInfo.setDirection(channel.getGpsDirection()); + gpsMsgInfo.setTime(channel.getGpsTime()); + } + // 无最新位置不发送 if (gpsMsgInfo != null) { - // 经纬度都为0不发送 - if (gpsMsgInfo.getLng() == 0 && gpsMsgInfo.getLat() == 0) { - continue; - } // 发送GPS消息 try { commanderForPlatform.sendNotifyMobilePosition(platform, gpsMsgInfo, channel, subscribe); @@ -877,7 +841,7 @@ public class PlatformServiceImpl implements IPlatformService { @Override public List queryEnablePlatformList(String serverId) { - return platformMapper.queryEnableParentPlatformList(serverId,true); + return platformMapper.queryEnableParentPlatformListByServerId(serverId,true); } @Override @@ -885,55 +849,23 @@ public class PlatformServiceImpl implements IPlatformService { public void delete(Integer platformId, CommonCallback callback) { Platform platform = platformMapper.query(platformId); Assert.notNull(platform, "平台不存在"); - // 发送离线消息,无论是否成功都删除缓存 - PlatformCatch platformCatch = redisCatchStorage.queryPlatformCatchInfo(platform.getServerGBId()); - if (platformCatch != null) { - String key = UUID.randomUUID().toString(); - dynamicTask.startDelay(key, ()->{ - deletePlatformInfo(platform); - if (callback != null) { - callback.run(null); - } - }, 2000); + if (statusTaskRunner.containsRegister(platform.getServerGBId())) { try { - commanderForPlatform.unregister(platform, platformCatch.getSipTransactionInfo(), (event -> { - dynamicTask.stop(key); - // 移除平台相关的信息 - deletePlatformInfo(platform); - if (callback != null) { - callback.run(null); - } - }), (event -> { - dynamicTask.stop(key); - // 移除平台相关的信息 - deletePlatformInfo(platform); - if (callback != null) { - callback.run(null); - } - })); - } catch (InvalidArgumentException | ParseException | SipException e) { - log.error("[命令发送失败] 国标级联 注销: {}", e.getMessage()); - } - }else { - deletePlatformInfo(platform); - if (callback != null) { - callback.run(null); - } + SipTransactionInfo transactionInfo = statusTaskRunner.getRegisterTransactionInfo(platform.getServerGBId()); + sendUnRegister(platform, transactionInfo); + }catch (Exception ignored) {} } + platformMapper.delete(platform.getId()); + statusTaskRunner.removeRegisterTask(platform.getServerGBId()); + statusTaskRunner.removeKeepAliveTask(platform.getServerGBId()); + + subscribeHolder.removeCatalogSubscribe(platform.getServerGBId()); + subscribeHolder.removeMobilePositionSubscribe(platform.getServerGBId()); } - @Transactional - public void deletePlatformInfo(Platform platform) { - // 删除关联的通道 - platformChannelMapper.removeChannelsByPlatformId(platform.getId()); - // 删除关联的分组 - platformChannelMapper.removePlatformGroupsByPlatformId(platform.getId()); - // 删除关联的行政区划 - platformChannelMapper.removePlatformRegionByPlatformId(platform.getId()); - // 删除redis缓存 - redisCatchStorage.delPlatformCatchInfo(platform.getServerGBId()); - // 删除平台信息 - platformMapper.delete(platform.getId()); + @Override + public List queryAll(String serverId) { + return platformMapper.queryByServerId(serverId); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java index 95e2e7905..7a07ae6fc 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java @@ -339,7 +339,7 @@ public class PlayServiceImpl implements IPlayService { InviteInfo inviteInfoInCatch = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId()); if (inviteInfoInCatch != null ) { if (inviteInfoInCatch.getStreamInfo() == null) { - // 释放生成的ssrc,使用上一次申请的322 + // 释放生成的ssrc,使用上一次申请的 ssrcFactory.releaseSsrc(mediaServerItem.getId(), ssrc); // 点播发起了但是尚未成功, 仅注册回调等待结果即可 @@ -1723,7 +1723,14 @@ public class PlayServiceImpl implements IPlayService { throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); } DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(channel.getGbId()); - play(device, deviceChannel, callback); + + MediaServer mediaServerItem = getNewMediaServerItem(device); + if (mediaServerItem == null) { + log.warn("[点播] 未找到可用的zlm deviceId: {},channelId:{}", device.getDeviceId(), deviceChannel.getDeviceId()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm"); + } + play(mediaServerItem, device, deviceChannel, null, record, callback); + } @Override diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/RegionServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/RegionServiceImpl.java index f40d8c429..b21832a73 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/RegionServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/RegionServiceImpl.java @@ -262,4 +262,66 @@ public class RegionServiceImpl implements IRegionService { regionList.addAll(allParent); return regionList; } + + @Override + public String getDescription(String civilCode) { + + CivilCodePo civilCodePo = CivilCodeUtil.INSTANCE.getCivilCodePo(civilCode); + Assert.notNull(civilCodePo, String.format("节点%s未查询到", civilCode)); + StringBuilder sb = new StringBuilder(); + sb.append(civilCodePo.getName()); + List civilCodePoList = CivilCodeUtil.INSTANCE.getAllParentCode(civilCode); + if (civilCodePoList.isEmpty()) { + return sb.toString(); + } + for (int i = 0; i < civilCodePoList.size(); i++) { + CivilCodePo item = civilCodePoList.get(i); + sb.insert(0, item.getName()); + if (i != civilCodePoList.size() - 1) { + sb.insert(0, "/"); + } + } + return sb.toString(); + } + + @Override + @Transactional + public void addByCivilCode(String civilCode) { + CivilCodePo civilCodePo = CivilCodeUtil.INSTANCE.getCivilCodePo(civilCode); + // 查询是否已经存在此节点 + Assert.notNull(civilCodePo, String.format("节点%s未查询到", civilCode)); + List civilCodePoList = CivilCodeUtil.INSTANCE.getAllParentCode(civilCode); + civilCodePoList.add(civilCodePo); + + Set civilCodeSet = regionMapper.queryInCivilCodePoList(civilCodePoList); + if (!civilCodeSet.isEmpty()) { + civilCodePoList.removeIf(item -> civilCodeSet.contains(item.getCode())); + } + if (civilCodePoList.isEmpty()) { + return; + } + int parentId = -1; + for (int i = civilCodePoList.size() - 1; i > -1; i--) { + CivilCodePo codePo = civilCodePoList.get(i); + + Region region = new Region(); + region.setDeviceId(codePo.getCode()); + region.setParentDeviceId(codePo.getParentCode()); + region.setName(civilCodePo.getName()); + region.setCreateTime(DateUtil.getNow()); + region.setUpdateTime(DateUtil.getNow()); + if (parentId == -1 && codePo.getParentCode() != null) { + Region parentRegion = regionMapper.queryByDeviceId(codePo.getParentCode()); + if (parentRegion == null){ + log.error(String.format("行政区划%sy已存在,但查询错误", codePo.getParentCode())); + throw new ControllerException(ErrorCode.ERROR100.getCode(), String.format("行政区划%sy已存在,但查询错误", codePo.getParentCode())); + } + region.setParentId(parentRegion.getId()); + }else { + region.setParentId(parentId); + } + regionMapper.add(region); + parentId = region.getId(); + } + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java index aaf6eff44..67f9c29d7 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.session; import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.UserSetting; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; @@ -13,6 +14,7 @@ import java.util.Set; /** * ssrc使用 */ +@Slf4j @Component public class SSRCFactory { @@ -93,6 +95,7 @@ public class SSRCFactory { String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId; Long size = redisTemplate.opsForSet().size(redisKey); if (size == null || size == 0) { + log.info("[获取 SSRC 失败] redisKey: {}", redisKey); throw new RuntimeException("ssrc已经用完"); } else { // 在集合中移除并返回一个随机成员。 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java deleted file mode 100755 index 8d1c7d2ee..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.task; - -import com.genersoft.iot.vmp.common.CommonCallback; - -/** - * @author lin - */ -public interface ISubscribeTask extends Runnable{ - void stop(CommonCallback callback); -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/SubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/SubscribeTask.java new file mode 100644 index 000000000..e33ac3813 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/SubscribeTask.java @@ -0,0 +1,49 @@ +package com.genersoft.iot.vmp.gb28181.task.deviceSubscribe; + +import com.genersoft.iot.vmp.common.SubscribeCallback; +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; +import lombok.Data; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; + +@Data +public abstract class SubscribeTask implements Delayed { + + private String deviceId; + + private SubscribeCallback callback; + + private SipTransactionInfo transactionInfo; + + /** + * 超时时间(单位: 毫秒) + */ + private long delayTime; + + public abstract void expired(); + + public abstract String getKey(); + + public abstract String getName(); + + @Override + public long getDelay(@NotNull TimeUnit unit) { + return unit.convert(delayTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); + } + + @Override + public int compareTo(@NotNull Delayed o) { + return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS)); + } + + public SubscribeTaskInfo getInfo(){ + SubscribeTaskInfo subscribeTaskInfo = new SubscribeTaskInfo(); + subscribeTaskInfo.setName(getName()); + subscribeTaskInfo.setTransactionInfo(transactionInfo); + subscribeTaskInfo.setDeviceId(deviceId); + subscribeTaskInfo.setKey(getKey()); + return subscribeTaskInfo; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/SubscribeTaskInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/SubscribeTaskInfo.java new file mode 100644 index 000000000..3a8741130 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/SubscribeTaskInfo.java @@ -0,0 +1,22 @@ +package com.genersoft.iot.vmp.gb28181.task.deviceSubscribe; + +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; +import lombok.Data; + +@Data +public class SubscribeTaskInfo { + + private String deviceId; + + private SipTransactionInfo transactionInfo; + + private String name; + + private String key; + + /** + * 过期时间 + */ + private long expireTime; + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/SubscribeTaskRunner.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/SubscribeTaskRunner.java new file mode 100644 index 000000000..7019121d3 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/SubscribeTaskRunner.java @@ -0,0 +1,135 @@ +package com.genersoft.iot.vmp.gb28181.task.deviceSubscribe; + +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; +import com.genersoft.iot.vmp.utils.redis.RedisUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Component +public class SubscribeTaskRunner{ + + private final Map subscribes = new ConcurrentHashMap<>(); + + private final DelayQueue delayQueue = new DelayQueue<>(); + + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private UserSetting userSetting; + + private final String prefix = "VMP_DEVICE_SUBSCRIBE"; + + // 订阅过期检查 + @Scheduled(fixedDelay = 500, timeUnit = TimeUnit.MILLISECONDS) + public void expirationCheck(){ + while (!delayQueue.isEmpty()) { + SubscribeTask take = null; + try { + take = delayQueue.take(); + try { + removeSubscribe(take.getKey()); + take.expired(); + }catch (Exception e) { + log.error("[设备订阅到期] {} 到期处理时出现异常, 设备编号: {} ", take.getName(), take.getDeviceId()); + } + } catch (InterruptedException e) { + log.error("[设备订阅任务] ", e); + } + } + } + + public void addSubscribe(SubscribeTask task) { + Duration duration = Duration.ofSeconds((task.getDelayTime() - System.currentTimeMillis())/1000); + if (duration.getSeconds() < 0) { + return; + } + subscribes.put(task.getKey(), task); + String key = String.format("%s_%s_%s", prefix, userSetting.getServerId(), task.getKey()); + redisTemplate.opsForValue().set(key, task.getInfo(), duration); + delayQueue.offer(task); + } + + public boolean removeSubscribe(String key) { + SubscribeTask task = subscribes.get(key); + if (task == null) { + return false; + } + String redisKey = String.format("%s_%s_%s", prefix, userSetting.getServerId(), task.getKey()); + redisTemplate.delete(redisKey); + subscribes.remove(key); + if (delayQueue.contains(task)) { + boolean remove = delayQueue.remove(task); + if (!remove) { + log.info("[移除订阅任务] 从延时队列内移除失败: {}", key); + } + } + return true; + } + + public SipTransactionInfo getTransactionInfo(String key) { + SubscribeTask task = subscribes.get(key); + if (task == null) { + return null; + } + return task.getTransactionInfo(); + } + + public boolean updateDelay(String key, long expirationTime) { + SubscribeTask task = subscribes.get(key); + if (task == null) { + return false; + } + log.info("[更新订阅任务时间] {}, 编号: {}", task.getName(), key); + if (delayQueue.contains(task)) { + boolean remove = delayQueue.remove(task); + if (!remove) { + log.info("[更新订阅任务时间] 从延时队列内移除失败: {}", key); + } + } + task.setDelayTime(expirationTime); + delayQueue.offer(task); + String redisKey = String.format("%s_%s_%s", prefix, userSetting.getServerId(), task.getKey()); + Duration duration = Duration.ofSeconds((expirationTime - System.currentTimeMillis())/1000); + redisTemplate.expire(redisKey, duration); + return true; + } + + public boolean containsKey(String key) { + return subscribes.containsKey(key); + } + + public List getAllTaskInfo(){ + String scanKey = String.format("%s_%s_*", prefix, userSetting.getServerId()); + List values = RedisUtil.scan(redisTemplate, scanKey); + if (values.isEmpty()) { + return new ArrayList<>(); + } + List result = new ArrayList<>(); + for (Object value : values) { + String redisKey = (String)value; + SubscribeTaskInfo taskInfo = (SubscribeTaskInfo)redisTemplate.opsForValue().get(redisKey); + if (taskInfo == null) { + continue; + } + Long expire = redisTemplate.getExpire(redisKey); + taskInfo.setExpireTime(expire); + result.add(taskInfo); + } + return result; + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/impl/SubscribeTaskForCatalog.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/impl/SubscribeTaskForCatalog.java new file mode 100644 index 000000000..8ca7b390e --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/impl/SubscribeTaskForCatalog.java @@ -0,0 +1,48 @@ +package com.genersoft.iot.vmp.gb28181.task.deviceSubscribe.impl; + +import com.genersoft.iot.vmp.common.SubscribeCallback; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; +import com.genersoft.iot.vmp.gb28181.task.deviceSubscribe.SubscribeTask; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SubscribeTaskForCatalog extends SubscribeTask { + + public static final String name = "catalog"; + + public static SubscribeTask getInstance(Device device, SubscribeCallback callback, SipTransactionInfo transactionInfo) { + if (device.getSubscribeCycleForCatalog() <= 0) { + return null; + } + SubscribeTaskForCatalog subscribeTaskForCatalog = new SubscribeTaskForCatalog(); + subscribeTaskForCatalog.setDelayTime((device.getSubscribeCycleForCatalog() * 1000L - 500L) + System.currentTimeMillis()); + subscribeTaskForCatalog.setDeviceId(device.getDeviceId()); + subscribeTaskForCatalog.setCallback(callback); + subscribeTaskForCatalog.setTransactionInfo(transactionInfo); + return subscribeTaskForCatalog; + } + + @Override + public void expired() { + if (super.getCallback() == null) { + log.info("[设备订阅到期] 目录订阅 未找到到期处理回调, 编号: {}", getDeviceId()); + return; + } + getCallback().run(getDeviceId(), getTransactionInfo()); + } + + @Override + public String getKey() { + return String.format("%s_%s", name, getDeviceId()); + } + + @Override + public String getName() { + return name; + } + + public static String getKey(Device device) { + return String.format("%s_%s", SubscribeTaskForCatalog.name, device.getDeviceId()); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/impl/SubscribeTaskForMobilPosition.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/impl/SubscribeTaskForMobilPosition.java new file mode 100644 index 000000000..5ff3c6198 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/deviceSubscribe/impl/SubscribeTaskForMobilPosition.java @@ -0,0 +1,48 @@ +package com.genersoft.iot.vmp.gb28181.task.deviceSubscribe.impl; + +import com.genersoft.iot.vmp.common.SubscribeCallback; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; +import com.genersoft.iot.vmp.gb28181.task.deviceSubscribe.SubscribeTask; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SubscribeTaskForMobilPosition extends SubscribeTask { + + public static final String name = "mobilPosition"; + + public static SubscribeTask getInstance(Device device, SubscribeCallback callback, SipTransactionInfo transactionInfo) { + if (device.getSubscribeCycleForCatalog() <= 0) { + return null; + } + SubscribeTaskForMobilPosition subscribeTaskForMobilPosition = new SubscribeTaskForMobilPosition(); + subscribeTaskForMobilPosition.setDelayTime((device.getSubscribeCycleForMobilePosition() * 1000L - 500L) + System.currentTimeMillis()); + subscribeTaskForMobilPosition.setDeviceId(device.getDeviceId()); + subscribeTaskForMobilPosition.setCallback(callback); + subscribeTaskForMobilPosition.setTransactionInfo(transactionInfo); + return subscribeTaskForMobilPosition; + } + + @Override + public void expired() { + if (super.getCallback() == null) { + log.info("[设备订阅到期] 移动位置订阅 未找到到期处理回调, 编号: {}", getDeviceId()); + return; + } + getCallback().run(getDeviceId(), getTransactionInfo()); + } + + @Override + public String getKey() { + return String.format("%s_%s", name, getDeviceId()); + } + + @Override + public String getName() { + return name; + } + + public static String getKey(Device device) { + return String.format("%s_%s", SubscribeTaskForMobilPosition.name, device.getDeviceId()); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java deleted file mode 100755 index e3f191242..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.task.impl; - -import com.genersoft.iot.vmp.common.CommonCallback; -import com.genersoft.iot.vmp.conf.DynamicTask; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; -import gov.nist.javax.sip.message.SIPRequest; -import lombok.extern.slf4j.Slf4j; - -import javax.sip.DialogState; -import javax.sip.InvalidArgumentException; -import javax.sip.ResponseEvent; -import javax.sip.SipException; -import javax.sip.header.ToHeader; -import java.text.ParseException; - -/** - * 目录订阅任务 - * @author lin - */ -@Slf4j -public class CatalogSubscribeTask implements ISubscribeTask { - private final Device device; - private final ISIPCommander sipCommander; - private SIPRequest request; - - private final DynamicTask dynamicTask; - - private final String taskKey = "catalog-subscribe-timeout"; - - - public CatalogSubscribeTask(Device device, ISIPCommander sipCommander, DynamicTask dynamicTask) { - this.device = device; - this.sipCommander = sipCommander; - this.dynamicTask = dynamicTask; - } - - @Override - public void run() { - if (dynamicTask.get(taskKey) != null) { - dynamicTask.stop(taskKey); - } - SIPRequest sipRequest = null; - try { - sipRequest = sipCommander.catalogSubscribe(device, request, eventResult -> { - ResponseEvent event = (ResponseEvent) eventResult.event; - // 成功 - log.info("[目录订阅]成功: {}", device.getDeviceId()); - ToHeader toHeader = (ToHeader)event.getResponse().getHeader(ToHeader.NAME); - try { - this.request.getToHeader().setTag(toHeader.getTag()); - } catch (ParseException e) { - log.info("[目录订阅]成功: 但为request设置ToTag失败"); - this.request = null; - } - },eventResult -> { - this.request = null; - // 失败 - log.warn("[目录订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); - dynamicTask.startDelay(taskKey, CatalogSubscribeTask.this, 2000); - }); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 目录订阅: {}", e.getMessage()); - - } - if (sipRequest != null) { - this.request = sipRequest; - } - } - - @Override - public void stop(CommonCallback callback) { - /** - * dialog 的各个状态 - * EARLY-> Early state状态-初始请求发送以后,收到了一个临时响应消息 - * CONFIRMED-> Confirmed Dialog状态-已确认 - * COMPLETED-> Completed Dialog状态-已完成 - * TERMINATED-> Terminated Dialog状态-终止 - */ - log.info("取消目录订阅时dialog状态为{}", DialogState.CONFIRMED); - if (dynamicTask.get(taskKey) != null) { - dynamicTask.stop(taskKey); - } - device.setSubscribeCycleForCatalog(0); - try { - sipCommander.catalogSubscribe(device, request, eventResult -> { - ResponseEvent event = (ResponseEvent) eventResult.event; - if (event.getResponse().getRawContent() != null) { - // 成功 - log.info("[取消目录订阅]成功: {}", device.getDeviceId()); - }else { - // 成功 - log.info("[取消目录订阅]成功: {}", device.getDeviceId()); - } - if (callback != null) { - callback.run(event.getResponse().getRawContent() != null); - } - },eventResult -> { - // 失败 - log.warn("[取消目录订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); - }); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 取消目录订阅: {}", e.getMessage()); - } - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java deleted file mode 100755 index 646b31eac..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.task.impl; - -import com.genersoft.iot.vmp.common.CommonCallback; -import com.genersoft.iot.vmp.conf.DynamicTask; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; -import gov.nist.javax.sip.message.SIPRequest; -import lombok.extern.slf4j.Slf4j; - -import javax.sip.InvalidArgumentException; -import javax.sip.ResponseEvent; -import javax.sip.SipException; -import javax.sip.header.ToHeader; -import java.text.ParseException; - -/** - * 移动位置订阅的定时更新 - * @author lin - */ -@Slf4j -public class MobilePositionSubscribeTask implements ISubscribeTask { - private final Device device; - private final ISIPCommander sipCommander; - - private SIPRequest request; - private final DynamicTask dynamicTask; - private final String taskKey = "mobile-position-subscribe-timeout"; - - public MobilePositionSubscribeTask(Device device, ISIPCommander sipCommander, DynamicTask dynamicTask) { - this.device = device; - this.sipCommander = sipCommander; - this.dynamicTask = dynamicTask; - } - - @Override - public void run() { - if (dynamicTask.get(taskKey) != null) { - dynamicTask.stop(taskKey); - } - SIPRequest sipRequest = null; - try { - sipRequest = sipCommander.mobilePositionSubscribe(device, request, eventResult -> { - // 成功 - log.info("[移动位置订阅]成功: {}", device.getDeviceId()); - ResponseEvent event = (ResponseEvent) eventResult.event; - ToHeader toHeader = (ToHeader)event.getResponse().getHeader(ToHeader.NAME); - try { - this.request.getToHeader().setTag(toHeader.getTag()); - } catch (ParseException e) { - log.info("[移动位置订阅]成功: 为request设置ToTag失败"); - this.request = null; - } - },eventResult -> { - this.request = null; - // 失败 - log.warn("[移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); - dynamicTask.startDelay(taskKey, MobilePositionSubscribeTask.this, 2000); - }); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 移动位置订阅: {}", e.getMessage()); - } - if (sipRequest != null) { - this.request = sipRequest; - } - - } - - @Override - public void stop(CommonCallback callback) { - /** - * dialog 的各个状态 - * EARLY-> Early state状态-初始请求发送以后,收到了一个临时响应消息 - * CONFIRMED-> Confirmed Dialog状态-已确认 - * COMPLETED-> Completed Dialog状态-已完成 - * TERMINATED-> Terminated Dialog状态-终止 - */ - if (dynamicTask.get(taskKey) != null) { - dynamicTask.stop(taskKey); - } - device.setSubscribeCycleForMobilePosition(0); - try { - sipCommander.mobilePositionSubscribe(device, request, eventResult -> { - ResponseEvent event = (ResponseEvent) eventResult.event; - if (event.getResponse().getRawContent() != null) { - // 成功 - log.info("[取消移动位置订阅]成功: {}", device.getDeviceId()); - }else { - // 成功 - log.info("[取消移动位置订阅]成功: {}", device.getDeviceId()); - } - if (callback != null) { - callback.run(event.getResponse().getRawContent() != null); - } - },eventResult -> { - // 失败 - log.warn("[取消移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); - }); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 取消移动位置订阅: {}", e.getMessage()); - } - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/platformStatus/PlatformKeepaliveTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/platformStatus/PlatformKeepaliveTask.java new file mode 100644 index 000000000..a1b2f400d --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/platformStatus/PlatformKeepaliveTask.java @@ -0,0 +1,64 @@ +package com.genersoft.iot.vmp.gb28181.task.platformStatus; + +import com.genersoft.iot.vmp.gb28181.bean.PlatformKeepaliveCallback; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; + +/** + * 平台心跳任务 + */ +@Slf4j +public class PlatformKeepaliveTask implements Delayed { + + @Getter + private String platformServerId; + + /** + * 超时时间(单位: 毫秒) + */ + @Getter + @Setter + private long delayTime; + + /** + * 到期回调 + */ + @Getter + private PlatformKeepaliveCallback callback; + + /** + * 心跳发送失败次数 + */ + @Getter + @Setter + private int failCount; + + public PlatformKeepaliveTask(String platformServerId, long delayTime, PlatformKeepaliveCallback callback) { + this.platformServerId = platformServerId; + this.delayTime = System.currentTimeMillis() + delayTime; + this.callback = callback; + } + + public void expired() { + if (callback == null) { + log.info("[平台心跳到期] 未找到到期处理回调, 平台上级编号: {}", platformServerId); + return; + } + getCallback().run(platformServerId, failCount); + } + + @Override + public long getDelay(@NotNull TimeUnit unit) { + return unit.convert(delayTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); + } + + @Override + public int compareTo(@NotNull Delayed o) { + return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS)); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/platformStatus/PlatformRegisterTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/platformStatus/PlatformRegisterTask.java new file mode 100644 index 000000000..781dc96f7 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/platformStatus/PlatformRegisterTask.java @@ -0,0 +1,70 @@ +package com.genersoft.iot.vmp.gb28181.task.platformStatus; + +import com.genersoft.iot.vmp.common.CommonCallback; +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; + +/** + * 平台注册任务 + */ +@Slf4j +public class PlatformRegisterTask implements Delayed { + + @Getter + private String platformServerId; + + /** + * 超时时间(单位: 毫秒) + */ + @Getter + @Setter + private long delayTime; + + @Getter + private SipTransactionInfo sipTransactionInfo; + + /** + * 到期回调 + */ + @Getter + private CommonCallback callback; + + + public PlatformRegisterTask(String platformServerId, long delayTime, SipTransactionInfo sipTransactionInfo, CommonCallback callback) { + this.platformServerId = platformServerId; + this.delayTime = System.currentTimeMillis() + delayTime; + this.callback = callback; + this.sipTransactionInfo = sipTransactionInfo; + } + + public void expired() { + if (callback == null) { + log.info("[平台注册到期] 未找到到期处理回调, 平台上级编号: {}", platformServerId); + return; + } + getCallback().run(platformServerId); + } + + @Override + public long getDelay(@NotNull TimeUnit unit) { + return unit.convert(delayTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); + } + + @Override + public int compareTo(@NotNull Delayed o) { + return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS)); + } + + public PlatformRegisterTaskInfo getInfo() { + PlatformRegisterTaskInfo taskInfo = new PlatformRegisterTaskInfo(); + taskInfo.setPlatformServerId(platformServerId); + taskInfo.setSipTransactionInfo(sipTransactionInfo); + return taskInfo; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/platformStatus/PlatformRegisterTaskInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/platformStatus/PlatformRegisterTaskInfo.java new file mode 100644 index 000000000..d7593eb90 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/platformStatus/PlatformRegisterTaskInfo.java @@ -0,0 +1,29 @@ +package com.genersoft.iot.vmp.gb28181.task.platformStatus; + +import com.genersoft.iot.vmp.common.CommonCallback; +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; + +/** + * 平台注册任务可序列化的信息 + */ +@Slf4j +@Data +public class PlatformRegisterTaskInfo{ + + private String platformServerId; + + private SipTransactionInfo sipTransactionInfo; + + /** + * 过期时间 + */ + private long expireTime; +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/platformStatus/PlatformStatusTaskRunner.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/platformStatus/PlatformStatusTaskRunner.java new file mode 100644 index 000000000..eaa96aedf --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/platformStatus/PlatformStatusTaskRunner.java @@ -0,0 +1,202 @@ +package com.genersoft.iot.vmp.gb28181.task.platformStatus; + +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; +import com.genersoft.iot.vmp.utils.redis.RedisUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Component +public class PlatformStatusTaskRunner { + + private final Map registerSubscribes = new ConcurrentHashMap<>(); + + private final DelayQueue registerDelayQueue = new DelayQueue<>(); + + private final Map keepaliveSubscribes = new ConcurrentHashMap<>(); + + private final DelayQueue keepaliveTaskDelayQueue = new DelayQueue<>(); + + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private UserSetting userSetting; + + private final String prefix = "VMP_PLATFORM_STATUS"; + + // 订阅过期检查 + @Scheduled(fixedDelay = 500, timeUnit = TimeUnit.MILLISECONDS) + public void expirationCheckForRegister(){ + while (!registerDelayQueue.isEmpty()) { + PlatformRegisterTask take = null; + try { + take = registerDelayQueue.take(); + try { + removeRegisterTask(take.getPlatformServerId()); + take.expired(); + }catch (Exception e) { + log.error("[平台注册到期] 到期处理时出现异常, 平台上级编号: {} ", take.getPlatformServerId()); + } + } catch (InterruptedException e) { + log.error("[平台注册到期] ", e); + } + } + } + @Scheduled(fixedDelay = 500, timeUnit = TimeUnit.MILLISECONDS) + public void expirationCheckForKeepalive(){ + while (!keepaliveTaskDelayQueue.isEmpty()) { + PlatformKeepaliveTask take = null; + try { + take = keepaliveTaskDelayQueue.take(); + try { + removeKeepAliveTask(take.getPlatformServerId()); + take.expired(); + }catch (Exception e) { + log.error("[平台心跳到期] 到期处理时出现异常, 平台上级编号: {} ", take.getPlatformServerId()); + } + } catch (InterruptedException e) { + log.error("[平台心跳到期] ", e); + } + } + } + + public void addRegisterTask(PlatformRegisterTask task) { + Duration duration = Duration.ofSeconds((task.getDelayTime() - System.currentTimeMillis())/1000); + if (duration.getSeconds() < 0) { + return; + } + registerSubscribes.put(task.getPlatformServerId(), task); + String key = String.format("%s_%s_%s", prefix, userSetting.getServerId(), task.getPlatformServerId()); + redisTemplate.opsForValue().set(key, task.getInfo(), duration); + registerDelayQueue.offer(task); + } + + public boolean removeRegisterTask(String platformServerId) { + PlatformRegisterTask task = registerSubscribes.get(platformServerId); + if (task != null) { + registerSubscribes.remove(platformServerId); + } + String redisKey = String.format("%s_%s_%s", prefix, userSetting.getServerId(), platformServerId); + redisTemplate.delete(redisKey); + if (registerDelayQueue.contains(task)) { + boolean remove = registerDelayQueue.remove(task); + if (!remove) { + log.info("[移除平台注册任务] 从延时队列内移除失败: {}", platformServerId); + } + } + return true; + } + + public SipTransactionInfo getRegisterTransactionInfo(String platformServerId) { + PlatformRegisterTask task = registerSubscribes.get(platformServerId); + if (task == null) { + return null; + } + return task.getSipTransactionInfo(); + } + + public boolean updateRegisterDelay(String platformServerId, long expirationTime) { + PlatformRegisterTask task = registerSubscribes.get(platformServerId); + if (task == null) { + return false; + } + log.info("[更新平台注册任务时间] 平台上级编号: {}", platformServerId); + if (registerDelayQueue.contains(task)) { + boolean remove = registerDelayQueue.remove(task); + if (!remove) { + log.info("[更新平台注册任务时间] 从延时队列内移除失败: {}", platformServerId); + } + } + task.setDelayTime(expirationTime); + registerDelayQueue.offer(task); + String redisKey = String.format("%s_%s_%s", prefix, userSetting.getServerId(), platformServerId); + Duration duration = Duration.ofSeconds((expirationTime - System.currentTimeMillis())/1000); + redisTemplate.expire(redisKey, duration); + return true; + } + + public boolean containsRegister(String platformServerId) { + return registerSubscribes.containsKey(platformServerId); + } + + public List getAllRegisterTaskInfo(){ + return getRegisterTransactionInfoByServerId(userSetting.getServerId()); + } + + public void addKeepAliveTask(PlatformKeepaliveTask task) { + Duration duration = Duration.ofSeconds((task.getDelayTime() - System.currentTimeMillis())/1000); + if (duration.getSeconds() < 0) { + return; + } + keepaliveSubscribes.put(task.getPlatformServerId(), task); + keepaliveTaskDelayQueue.offer(task); + } + + public boolean removeKeepAliveTask(String platformServerId) { + PlatformKeepaliveTask task = keepaliveSubscribes.get(platformServerId); + if (task != null) { + keepaliveSubscribes.remove(platformServerId); + } + if (keepaliveTaskDelayQueue.contains(task)) { + boolean remove = keepaliveTaskDelayQueue.remove(task); + if (!remove) { + log.info("[移除平台心跳任务] 从延时队列内移除失败: {}", platformServerId); + } + } + return true; + } + + public boolean updateKeepAliveDelay(String platformServerId, long expirationTime) { + PlatformKeepaliveTask task = keepaliveSubscribes.get(platformServerId); + if (task == null) { + return false; + } + log.info("[更新平台心跳任务时间] 平台上级编号: {}", platformServerId); + if (keepaliveTaskDelayQueue.contains(task)) { + boolean remove = keepaliveTaskDelayQueue.remove(task); + if (!remove) { + log.info("[更新平台心跳任务时间] 从延时队列内移除失败: {}", platformServerId); + } + } + task.setDelayTime(expirationTime); + keepaliveTaskDelayQueue.offer(task); + return true; + } + + public boolean containsKeepAlive(String platformServerId) { + return keepaliveSubscribes.containsKey(platformServerId); + } + + public List getRegisterTransactionInfoByServerId(String serverId) { + String scanKey = String.format("%s_%s_*", prefix, serverId); + List values = RedisUtil.scan(redisTemplate, scanKey); + if (values.isEmpty()) { + return new ArrayList<>(); + } + List result = new ArrayList<>(); + for (Object value : values) { + String redisKey = (String)value; + PlatformRegisterTaskInfo taskInfo = (PlatformRegisterTaskInfo)redisTemplate.opsForValue().get(redisKey); + if (taskInfo == null) { + continue; + } + Long expire = redisTemplate.getExpire(redisKey); + taskInfo.setExpireTime(expire); + result.add(taskInfo); + } + return result; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java index b7892dbd3..3ac4be1bf 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java @@ -84,24 +84,23 @@ public class SIPProcessorObserver implements ISIPProcessorObserver { // Success if (((status >= Response.OK) && (status < Response.MULTIPLE_CHOICES)) || status == Response.UNAUTHORIZED) { - if (status != Response.UNAUTHORIZED && responseEvent.getResponse() != null && !sipSubscribe.isEmpty() ) { - CallIdHeader callIdHeader = response.getCallIdHeader(); - CSeqHeader cSeqHeader = response.getCSeqHeader(); - if (callIdHeader != null) { - SipEvent sipEvent = sipSubscribe.getSubscribe(callIdHeader.getCallId() + cSeqHeader.getSeqNumber()); - if (sipEvent != null) { - if (sipEvent.getOkEvent() != null) { - SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult<>(responseEvent); - sipEvent.getOkEvent().response(eventResult); - } - sipSubscribe.removeSubscribe(callIdHeader.getCallId() + cSeqHeader.getSeqNumber()); - } - } - } ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(response.getCSeqHeader().getMethod()); if (sipRequestProcessor != null) { sipRequestProcessor.process(responseEvent); } + + CallIdHeader callIdHeader = response.getCallIdHeader(); + CSeqHeader cSeqHeader = response.getCSeqHeader(); + if (callIdHeader != null) { + SipEvent sipEvent = sipSubscribe.getSubscribe(callIdHeader.getCallId() + cSeqHeader.getSeqNumber()); + if (sipEvent != null) { + if (sipEvent.getOkEvent() != null) { + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult<>(responseEvent); + sipEvent.getOkEvent().response(eventResult); + } + sipSubscribe.removeSubscribe(callIdHeader.getCallId() + cSeqHeader.getSeqNumber()); + } + } } else if ((status >= Response.TRYING) && (status < Response.OK)) { // 增加其它无需回复的响应,如101、180等 // 更新sip订阅的时间 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java index ba2a04432..8c6ebf4e2 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java @@ -2,21 +2,22 @@ package com.genersoft.iot.vmp.gb28181.transmit; import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.gb28181.SipLayer; +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.event.sip.SipEvent; import com.genersoft.iot.vmp.gb28181.utils.SipUtils; import com.genersoft.iot.vmp.utils.GitUtil; import gov.nist.javax.sip.SipProviderImpl; +import gov.nist.javax.sip.address.SipUri; +import gov.nist.javax.sip.message.SIPRequest; +import gov.nist.javax.sip.message.SIPResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import javax.sip.SipException; -import javax.sip.header.CSeqHeader; -import javax.sip.header.CallIdHeader; -import javax.sip.header.UserAgentHeader; -import javax.sip.header.ViaHeader; +import javax.sip.header.*; import javax.sip.message.Message; import javax.sip.message.Request; import javax.sip.message.Response; @@ -39,6 +40,7 @@ public class SIPSender { @Autowired private SipSubscribe sipSubscribe; + @Autowired private SipConfig sipConfig; @@ -73,6 +75,7 @@ public class SIPSender { if (okEvent != null || errorEvent != null) { CallIdHeader callIdHeader = (CallIdHeader) message.getHeader(CallIdHeader.NAME); CSeqHeader cSeqHeader = (CSeqHeader) message.getHeader(CSeqHeader.NAME); + FromHeader fromHeader = (FromHeader) message.getHeader(FromHeader.NAME); String key = callIdHeader.getCallId() + cSeqHeader.getSeqNumber(); SipEvent sipEvent = SipEvent.getInstance(key, eventResult -> { sipSubscribe.removeSubscribe(key); @@ -85,6 +88,28 @@ public class SIPSender { errorEvent.response(eventResult); } }), timeout == null ? sipConfig.getTimeout() : timeout); + SipTransactionInfo sipTransactionInfo = new SipTransactionInfo(); + sipTransactionInfo.setFromTag(fromHeader.getTag()); + sipTransactionInfo.setCallId(callIdHeader.getCallId()); + + if (message instanceof SIPResponse) { + SIPResponse response = (SIPResponse) message; + sipTransactionInfo.setToTag(response.getToHeader().getTag()); + sipTransactionInfo.setViaBranch(response.getTopmostViaHeader().getBranch()); + }else if (message instanceof SIPRequest) { + SIPRequest request = (SIPRequest) message; + sipTransactionInfo.setViaBranch(request.getTopmostViaHeader().getBranch()); + SipUri sipUri = (SipUri)request.getRequestLine().getUri(); + sipTransactionInfo.setUser(sipUri.getUser()); + } + + + + ExpiresHeader expiresHeader = (ExpiresHeader) message.getHeader(ExpiresHeader.NAME); + if (expiresHeader != null) { + sipTransactionInfo.setExpires(expiresHeader.getExpires()); + } + sipEvent.setSipTransactionInfo(sipTransactionInfo); sipSubscribe.addSubscribe(key, sipEvent); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java index 784a73c64..4d252d5d2 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java @@ -17,16 +17,16 @@ import javax.sip.InvalidArgumentException; import javax.sip.SipException; import java.text.ParseException; -/** - * @description:设备能力接口,用于定义设备的控制、查询能力 +/** + * @description:设备能力接口,用于定义设备的控制、查询能力 * @author: swwheihei - * @date: 2020年5月3日 下午9:16:34 + * @date: 2020年5月3日 下午9:16:34 */ public interface ISIPCommander { /** * 云台控制,支持方向与缩放控制 - * + * * @param device 控制设备 * @param channelId 预览通道 * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 @@ -36,10 +36,10 @@ public interface ISIPCommander { * @param zoomSpeed 镜头缩放速度 */ void ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) throws InvalidArgumentException, SipException, ParseException; - + /** * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 - * + * * @param device 控制设备 * @param channelId 预览通道 * @param cmdCode 指令码 @@ -48,7 +48,7 @@ public interface ISIPCommander { * @param combineCode2 组合码2 */ void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException; - + /** * 前端控制指令(用于转发上级指令) * @param device 控制设备 @@ -66,7 +66,7 @@ public interface ISIPCommander { /** * 请求回放视频流 - * + * * @param device 视频设备 * @param channel 预览通道 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss @@ -76,13 +76,13 @@ public interface ISIPCommander { /** * 请求历史媒体下载 - * + * * @param device 视频设备 * @param channel 预览通道 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss * @param downloadSpeed 下载倍速参数 - */ + */ void downloadStreamCmd(MediaServer mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel, String startTime, String endTime, int downloadSpeed, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent, Long timeout) throws InvalidArgumentException, SipException, ParseException; @@ -116,7 +116,7 @@ public interface ISIPCommander { * 回放倍速播放 */ void playSpeedCmd(Device device, DeviceChannel channel, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException; - + /** * 回放控制 * @param device @@ -138,39 +138,39 @@ public interface ISIPCommander { /** * 音视频录像控制 - * + * * @param device 视频设备 * @param channelId 预览通道 * @param recordCmdStr 录像命令:Record / StopRecord */ void recordCmd(Device device, String channelId, String recordCmdStr, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; - + /** * 远程启动控制命令 - * + * * @param device 视频设备 */ void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException; /** * 报警布防/撤防命令 - * + * * @param device 视频设备 */ void guardCmd(Device device, String guardCmdStr, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; - + /** * 报警复位命令 - * + * * @param device 视频设备 * @param alarmMethod 报警方式(可选) * @param alarmType 报警类型(可选) */ void alarmResetCmd(Device device, String alarmMethod, String alarmType, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; - + /** * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 - * + * * @param device 视频设备 * @param channelId 预览通道 */ @@ -184,11 +184,11 @@ public interface ISIPCommander { /** * 设备配置命令 - * + * * @param device 视频设备 */ void deviceConfigCmd(Device device); - + /** * 设备配置命令:basicParam */ @@ -196,11 +196,11 @@ public interface ISIPCommander { /** * 查询设备状态 - * + * * @param device 视频设备 */ void deviceStatusQuery(Device device, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; - + /** * 查询设备信息 * @@ -209,27 +209,27 @@ public interface ISIPCommander { * @return */ void deviceInfoQuery(Device device, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; - + /** * 查询目录列表 - * + * * @param device 视频设备 */ void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException; - + /** * 查询录像信息 - * + * * @param device 视频设备 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss * @param sn */ void recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer Secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; - + /** * 查询报警信息 - * + * * @param device 视频设备 * @param startPriority 报警起始级别(可选) * @param endPriority 报警终止级别(可选) @@ -241,37 +241,37 @@ public interface ISIPCommander { */ void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; - + /** * 查询设备配置 - * + * * @param device 视频设备 * @param channelId 通道编码(可选) * @param configType 配置类型: */ void deviceConfigQuery(Device device, String channelId, String configType, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; - + /** * 查询设备预置位置 - * + * * @param device 视频设备 */ void presetQuery(Device device, String channelId, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; - + /** * 查询移动设备位置数据 - * + * * @param device 视频设备 */ void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 订阅、取消订阅移动位置 - * + * * @param device 视频设备 * @return true = 命令发送成功 */ - SIPRequest mobilePositionSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + SIPRequest mobilePositionSubscribe(Device device, SipTransactionInfo transactionInfo, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 订阅、取消订阅报警信息 @@ -290,7 +290,7 @@ public interface ISIPCommander { * @param device 视频设备 * @return true = 命令发送成功 */ - SIPRequest catalogSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + SIPRequest catalogSubscribe(Device device, SipTransactionInfo transactionInfo, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; /** * 拉框控制命令 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java index 4b7176590..8e3fb4b36 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java @@ -34,7 +34,7 @@ public class SIPRequestHeaderPlarformProvider { @Autowired private SipConfig sipConfig; - + @Autowired private SipLayer sipLayer; @@ -225,11 +225,11 @@ public class SIPRequestHeaderPlarformProvider { SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(), parentPlatform.getDeviceIp() + ":" + parentPlatform.getDevicePort()); Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, subscribeInfo.getResponse() != null ? subscribeInfo.getResponse().getToTag(): subscribeInfo.getSimulatedToTag()); + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, subscribeInfo.getTransactionInfo() != null ? subscribeInfo.getTransactionInfo() .getToTag(): subscribeInfo.getSimulatedToTag()); // to SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerGBDomain()); Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, subscribeInfo.getRequest() != null ?subscribeInfo.getRequest().getFromTag(): subscribeInfo.getSimulatedFromTag()); + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, subscribeInfo.getTransactionInfo() != null ?subscribeInfo.getTransactionInfo().getFromTag(): subscribeInfo.getSimulatedFromTag()); // Forwards MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); @@ -239,7 +239,7 @@ public class SIPRequestHeaderPlarformProvider { // 设置编码, 防止中文乱码 messageFactory.setDefaultContentEncodingCharset("gb2312"); - CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(subscribeInfo.getRequest() != null ? subscribeInfo.getRequest().getCallIdHeader().getCallId(): subscribeInfo.getSimulatedCallId()); + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(subscribeInfo.getTransactionInfo() != null ? subscribeInfo.getTransactionInfo().getCallId(): subscribeInfo.getSimulatedCallId()); request = (SIPRequest) messageFactory.createRequest(requestURI, Request.NOTIFY, callIdHeader, cSeqHeader, fromHeader, toHeader, viaHeaders, maxForwards); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java index 7bfd91bfa..3c084f7ce 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java @@ -33,7 +33,7 @@ public class SIPRequestHeaderProvider { @Autowired private SipConfig sipConfig; - + @Autowired private SipLayer sipLayer; @@ -43,7 +43,7 @@ public class SIPRequestHeaderProvider { @Autowired private IRedisCatchStorage redisCatchStorage; - + public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { Request request = null; // sipuri @@ -76,7 +76,7 @@ public class SIPRequestHeaderProvider { request.setContent(content, contentTypeHeader); return request; } - + public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { Request request = null; //请求行 @@ -96,10 +96,10 @@ public class SIPRequestHeaderProvider { SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null); - + //Forwards MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); - + //ceq CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE); request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); @@ -116,7 +116,7 @@ public class SIPRequestHeaderProvider { request.setContent(content, contentTypeHeader); return request; } - + public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException { Request request = null; //请求行 @@ -134,14 +134,14 @@ public class SIPRequestHeaderProvider { SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null); - + //Forwards MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); - + //ceq CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE); request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards); - + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort())); // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort())); request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress)); @@ -231,7 +231,7 @@ public class SIPRequestHeaderProvider { return request; } - public Request createSubscribeRequest(Device device, String content, SIPRequest requestOld, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { + public Request createSubscribeRequest(Device device, String content, SipTransactionInfo sipTransactionInfo, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException { Request request = null; // sipuri SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); @@ -244,11 +244,11 @@ public class SIPRequestHeaderProvider { // from SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain()); Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI); - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, requestOld == null ? SipUtils.getNewFromTag() :requestOld.getFromTag()); + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, sipTransactionInfo == null ? SipUtils.getNewFromTag() :sipTransactionInfo.getFromTag()); // to SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, requestOld == null ? null :requestOld.getToTag()); + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, sipTransactionInfo == null ? null :sipTransactionInfo.getToTag()); // Forwards MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 9ac1c6aa1..fd53e18e9 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -1106,7 +1106,9 @@ public class SIPCommander implements ISIPCommander { Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, eventResult -> { messageSubscribe.removeSubscribe(messageEvent.getKey()); - callback.run(ErrorCode.ERROR100.getCode(), "失败," + eventResult.msg, null); + if (callback != null) { + callback.run(ErrorCode.ERROR100.getCode(), "失败," + eventResult.msg, null); + } }); } @@ -1177,7 +1179,7 @@ public class SIPCommander implements ISIPCommander { * @return true = 命令发送成功 */ @Override - public SIPRequest mobilePositionSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + public SIPRequest mobilePositionSubscribe(Device device, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { StringBuffer subscribePostitionXml = new StringBuffer(200); String charset = device.getCharset(); @@ -1195,12 +1197,12 @@ public class SIPCommander implements ISIPCommander { CallIdHeader callIdHeader; - if (requestOld != null) { - callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); + if (sipTransactionInfo != null) { + callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(sipTransactionInfo.getCallId()); } else { callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()); } - SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), requestOld, device.getSubscribeCycleForMobilePosition(), "presence",callIdHeader); //Position;id=" + tm.substring(tm.length() - 4)); + SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), sipTransactionInfo, device.getSubscribeCycleForMobilePosition(), "presence",callIdHeader); //Position;id=" + tm.substring(tm.length() - 4)); sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); return request; @@ -1253,7 +1255,7 @@ public class SIPCommander implements ISIPCommander { } @Override - public SIPRequest catalogSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + public SIPRequest catalogSubscribe(Device device, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { StringBuffer cmdXml = new StringBuffer(200); String charset = device.getCharset(); @@ -1266,14 +1268,14 @@ public class SIPCommander implements ISIPCommander { CallIdHeader callIdHeader; - if (requestOld != null) { - callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId()); + if (sipTransactionInfo != null) { + callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(sipTransactionInfo.getCallId()); } else { callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()); } // 有效时间默认为60秒以上 - SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, cmdXml.toString(), requestOld, device.getSubscribeCycleForCatalog(), "Catalog", + SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, cmdXml.toString(), sipTransactionInfo, device.getSubscribeCycleForCatalog(), "Catalog", callIdHeader); sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent); return request; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderForPlatform.java index 5e5a207b6..8ad0a6c2f 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderForPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderForPlatform.java @@ -21,7 +21,6 @@ import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.utils.GitUtil; import gov.nist.javax.sip.message.MessageFactoryImpl; @@ -121,9 +120,6 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform { request = headerProviderPlatformProvider.createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(), fromTag, toTag, callIdHeader, isRegister? parentPlatform.getExpires() : 0); - // 将 callid 写入缓存, 等注册成功可以更新状态 - String callIdFromHeader = callIdHeader.getCallId(); - redisCatchStorage.updatePlatformRegisterInfo(callIdFromHeader, PlatformRegisterInfo.getInstance(parentPlatform.getServerGBId(), isRegister)); }else { request = headerProviderPlatformProvider.createRegisterRequest(parentPlatform, fromTag, toTag, www, callIdHeader, isRegister? parentPlatform.getExpires() : 0); } @@ -132,11 +128,10 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform { if (event != null) { log.info("[国标级联]:{}, 注册失败: {} ", parentPlatform.getServerGBId(), event.msg); } - redisCatchStorage.delPlatformRegisterInfo(callIdHeader.getCallId()); if (errorEvent != null ) { errorEvent.response(event); } - }, okEvent, 5L); + }, okEvent, 2000L); } @Override @@ -369,7 +364,7 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform { .append("MobilePosition\r\n") .append("" + (int)((Math.random()*9+1)*100000) + "\r\n") .append("" + channel.getGbDeviceId() + "\r\n") - .append("\r\n") + .append("\r\n") .append("" + gpsMsgInfo.getLng() + "\r\n") .append("" + gpsMsgInfo.getLat() + "\r\n") .append("" + gpsMsgInfo.getSpeed() + "\r\n") diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java index 26a886b78..bacf50456 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java @@ -143,39 +143,44 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In mediaServerService.releaseSsrc(mediaInfo.getId(), sendRtpItem.getSsrc()); } } - MediaServer mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId()); - if (mediaServer != null) { - AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getChannelId()); - if (audioBroadcastCatch != null && audioBroadcastCatch.getSipTransactionInfo().getCallId().equals(callIdHeader.getCallId())) { - // 来自上级平台的停止对讲 - log.info("[停止对讲] 来自上级,平台:{}, 通道:{}", sendRtpItem.getTargetId(), sendRtpItem.getChannelId()); - audioBroadcastManager.del(sendRtpItem.getChannelId()); - } + if (sendRtpItem.getServerId().equals(userSetting.getServerId())) { + MediaServer mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId()); + if (mediaServer != null) { + AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(sendRtpItem.getChannelId()); + if (audioBroadcastCatch != null && audioBroadcastCatch.getSipTransactionInfo().getCallId().equals(callIdHeader.getCallId())) { + // 来自上级平台的停止对讲 + log.info("[停止对讲] 来自上级,平台:{}, 通道:{}", sendRtpItem.getTargetId(), sendRtpItem.getChannelId()); + audioBroadcastManager.del(sendRtpItem.getChannelId()); + } - MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, sendRtpItem.getApp(), streamId); + MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, sendRtpItem.getApp(), streamId); - if (mediaInfo.getReaderCount() <= 0) { - log.info("[收到bye] {} 无其它观看者,通知设备停止推流", streamId); - if (sendRtpItem.getPlayType().equals(InviteStreamType.PLAY)) { - Device device = deviceService.getDeviceByDeviceId(sendRtpItem.getTargetId()); - if (device == null) { - log.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId); - return; - } - DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(sendRtpItem.getChannelId()); - if (deviceChannel == null) { - log.info("[收到bye] {} 通知设备停止推流时未找到通道信息", streamId); - return; - } - try { - log.info("[停止点播] {}/{}", sendRtpItem.getTargetId(), sendRtpItem.getChannelId()); - cmder.streamByeCmd(device, deviceChannel.getDeviceId(), sendRtpItem.getApp(), sendRtpItem.getStream(), null, null); - } catch (InvalidArgumentException | ParseException | SipException | - SsrcTransactionNotFoundException e) { - log.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage()); + if (mediaInfo != null && mediaInfo.getReaderCount() <= 0) { + log.info("[收到bye] {} 无其它观看者,通知设备停止推流", streamId); + if (sendRtpItem.getPlayType().equals(InviteStreamType.PLAY)) { + Device device = deviceService.getDeviceByDeviceId(sendRtpItem.getTargetId()); + if (device == null) { + log.info("[收到bye] {} 通知设备停止推流时未找到设备信息", streamId); + return; + } + DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(sendRtpItem.getChannelId()); + if (deviceChannel == null) { + log.info("[收到bye] {} 通知设备停止推流时未找到通道信息", streamId); + return; + } + try { + log.info("[停止点播] {}/{}", sendRtpItem.getTargetId(), sendRtpItem.getChannelId()); + cmder.streamByeCmd(device, deviceChannel.getDeviceId(), sendRtpItem.getApp(), sendRtpItem.getStream(), null, null); + } catch (InvalidArgumentException | ParseException | SipException | + SsrcTransactionNotFoundException e) { + log.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage()); + } } } } + } else { + // TODO 流再其他wvp上时应该通知这个wvp停止推流和发送BYE + } } // 可能是设备发送的停止 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index 4ddbc22be..5ba83e85b 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java @@ -172,10 +172,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements // 点播成功, TODO 可以在此处检测cancel命令是否存在,存在则不发送 if (userSetting.getUseCustomSsrcForParentInvite()) { // 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式 - String ssrc = "Play".equalsIgnoreCase(inviteInfo.getSessionName()) + MediaServer mediaServer = mediaServerService.getOne(streamInfo.getMediaServer().getId()); + if (mediaServer != null) { + String ssrc = "Play".equalsIgnoreCase(inviteInfo.getSessionName()) ? ssrcFactory.getPlaySsrc(streamInfo.getMediaServer().getId()) - : ssrcFactory.getPlayBackSsrc(streamInfo.getMediaServer().getId()); - inviteInfo.setSsrc(ssrc); + : ssrcFactory.getPlayBackSsrc(streamInfo.getMediaServer().getId()); + inviteInfo.setSsrc(ssrc); + } } // 构建sendRTP内容 SendRtpInfo sendRtpItem = sendRtpServerService.createSendRtpInfo(streamInfo.getMediaServer(), @@ -628,8 +631,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements request.getCallIdHeader().getCallId(), sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getSsrc(), sendRtpItem.getMediaServerId(), sipResponse, InviteSessionType.BROADCAST); sessionManager.put(ssrcTransaction); // 开启发流,大华在收到200OK后就会开始建立连接 - if (!device.isBroadcastPushAfterAck()) { - log.info("[语音喊话] 回复200OK后发现 BroadcastPushAfterAck为False,现在开始推流"); + if (sendRtpItem.isTcpActive() || !device.isBroadcastPushAfterAck()) { + if (sendRtpItem.isTcpActive()) { + log.info("[语音喊话] 监听端口等待设备连接后推流"); + }else { + log.info("[语音喊话] 回复200OK后发现 BroadcastPushAfterAck为False,现在开始推流"); + } + playService.startPushStream(sendRtpItem, channel, sipResponse, parentPlatform, request.getCallIdHeader()); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java index 85eff4105..5b05ec113 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java @@ -5,7 +5,7 @@ import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.GbSipDate; -import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo; +import com.genersoft.iot.vmp.common.RemoteAddressInfo; import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java index acdff1ce3..e2793d5f2 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java @@ -1,9 +1,6 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; -import com.genersoft.iot.vmp.gb28181.bean.CmdType; -import com.genersoft.iot.vmp.gb28181.bean.Platform; -import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; -import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo; +import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.service.IPlatformService; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; @@ -23,6 +20,7 @@ import org.springframework.stereotype.Component; import javax.sip.InvalidArgumentException; import javax.sip.RequestEvent; import javax.sip.SipException; +import javax.sip.header.EventHeader; import javax.sip.header.ExpiresHeader; import javax.sip.message.Response; import java.text.ParseException; @@ -56,9 +54,9 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme sipProcessorObserver.addRequestProcessor(method, this); } - /** - * 处理SUBSCRIBE请求 - * + /** + * 处理SUBSCRIBE请求 + * * @param evt 事件 */ @Override @@ -72,6 +70,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme return; } String cmd = XmlUtil.getText(rootElement, "CmdType"); + log.info("[收到订阅请求] 类型: {}", cmd); if (CmdType.MOBILE_POSITION.equals(cmd)) { processNotifyMobilePosition(request, rootElement); // } else if (CmdType.ALARM.equals(cmd)) { @@ -106,7 +105,6 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme String platformId = SipUtils.getUserIdFromFromHeader(request); String deviceId = XmlUtil.getText(rootElement, "DeviceID"); Platform platform = platformService.queryPlatformByServerGBId(platformId); - SubscribeInfo subscribeInfo = new SubscribeInfo(request, platformId); if (platform == null) { return; } @@ -122,23 +120,28 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme .append("OK\r\n") .append("\r\n"); - if (subscribeInfo.getExpires() > 0) { - // GPS上报时间间隔 - String interval = XmlUtil.getText(rootElement, "Interval"); - if (interval == null) { - subscribeInfo.setGpsInterval(5); - }else { - subscribeInfo.setGpsInterval(Integer.parseInt(interval)); - } - subscribeInfo.setSn(sn); - } + try { - SIPResponse response = responseXmlAck(request, resultXml.toString(), platform, subscribeInfo.getExpires()); + int expires = request.getExpires().getExpires(); + SIPResponse response = responseXmlAck(request, resultXml.toString(), platform, expires); + + SubscribeInfo subscribeInfo = SubscribeInfo.getInstance(response, platformId, expires, + (EventHeader)request.getHeader(EventHeader.NAME)); + if (subscribeInfo.getExpires() > 0) { + // GPS上报时间间隔 + String interval = XmlUtil.getText(rootElement, "Interval"); + if (interval == null) { + subscribeInfo.setGpsInterval(5); + }else { + subscribeInfo.setGpsInterval(Integer.parseInt(interval)); + } + subscribeInfo.setSn(sn); + } if (subscribeInfo.getExpires() == 0) { subscribeHolder.removeMobilePositionSubscribe(platformId); }else { - subscribeInfo.setResponse(response); + subscribeInfo.setTransactionInfo(new SipTransactionInfo(response)); subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo, ()->{ platformService.sendNotifyMobilePosition(platformId); }); @@ -155,15 +158,16 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme private void processNotifyCatalogList(SIPRequest request, Element rootElement) throws SipException { if (request == null) { + log.info("[处理目录订阅] 发现request为NUll。已忽略"); return; } String platformId = SipUtils.getUserIdFromFromHeader(request); String deviceId = XmlUtil.getText(rootElement, "DeviceID"); Platform platform = platformService.queryPlatformByServerGBId(platformId); if (platform == null){ + log.info("[处理目录订阅] 未找到平台 {}。已忽略", platformId); return; } - SubscribeInfo subscribeInfo = new SubscribeInfo(request, platformId); String sn = XmlUtil.getText(rootElement, "SN"); log.info("[回复上级的目录订阅请求]: {}/{}", platformId, deviceId); @@ -176,18 +180,19 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme .append("OK\r\n") .append("\r\n"); - if (subscribeInfo.getExpires() > 0) { - subscribeHolder.putCatalogSubscribe(platformId, subscribeInfo); - }else if (subscribeInfo.getExpires() == 0) { - subscribeHolder.removeCatalogSubscribe(platformId); - } + try { + int expires = request.getExpires().getExpires(); Platform parentPlatform = platformService.queryPlatformByServerGBId(platformId); - SIPResponse response = responseXmlAck(request, resultXml.toString(), parentPlatform, subscribeInfo.getExpires()); + SIPResponse response = responseXmlAck(request, resultXml.toString(), parentPlatform, expires); + + SubscribeInfo subscribeInfo = SubscribeInfo.getInstance(response, platformId, expires, + (EventHeader)request.getHeader(EventHeader.NAME)); + if (subscribeInfo.getExpires() == 0) { subscribeHolder.removeCatalogSubscribe(platformId); }else { - subscribeInfo.setResponse(response); + subscribeInfo.setTransactionInfo(new SipTransactionInfo(response)); subscribeHolder.putCatalogSubscribe(platformId, subscribeInfo); } } catch (SipException | InvalidArgumentException | ParseException e) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java index 04d6a0ca4..cdaea441d 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java @@ -5,7 +5,7 @@ import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Platform; -import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo; +import com.genersoft.iot.vmp.common.RemoteAddressInfo; import com.genersoft.iot.vmp.gb28181.bean.SipMsgInfo; import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; @@ -97,10 +97,6 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp } Device device = sipMsgInfo.getDevice(); SIPRequest request = (SIPRequest) evt.getRequest(); -// if (!ObjectUtils.isEmpty(device.getKeepaliveTime()) && DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L) { -// log.info("[收到心跳] 心跳发送过于频繁,已忽略 device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId()); -// return; -// } RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress()); if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) { @@ -109,12 +105,6 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort()))); device.setIp(remoteAddressInfo.getIp()); device.setLocalIp(request.getLocalAddress().getHostAddress()); - // 设备地址变化会引起目录订阅任务失效,需要重新添加 - if (device.getSubscribeCycleForCatalog() > 0) { - deviceService.removeCatalogSubscribe(device, result -> { - deviceService.addCatalogSubscribe(device); - }); - } } device.setKeepaliveTime(DateUtil.getNow()); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java index f8bb55703..b25eef3d3 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java @@ -78,7 +78,7 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen String channelId = getText(rootElementAfterCharset, "DeviceID"); DeviceChannel deviceChannel = deviceChannelService.getOne(device.getDeviceId(), channelId); if (deviceChannel == null) { - log.warn("[解析报警消息] 未找到通道:{}/{}", device.getDeviceId(), channelId); + log.warn("[解析移动位置通知] 未找到通道:{}/{}", device.getDeviceId(), channelId); continue; } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java index 6801622c8..6a1349d44 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java @@ -45,7 +45,7 @@ public class ResponseMessageHandler extends MessageHandlerAbstract implements In String cmd = getText(element, "CmdType"); String sn = getText(element, "SN"); MessageEvent subscribe = (MessageEvent)messageSubscribe.getSubscribe(cmd + sn); - if (subscribe != null) { + if (subscribe != null && subscribe.getCallback() != null) { String result = getText(element, "Result"); if (result == null || "OK".equalsIgnoreCase(result) || data != null) { subscribe.getCallback().run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), data); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java index 3564e86c5..1f73370b1 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java @@ -1,14 +1,14 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl; import com.genersoft.iot.vmp.gb28181.bean.Platform; -import com.genersoft.iot.vmp.gb28181.bean.PlatformCatch; import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; +import com.genersoft.iot.vmp.gb28181.event.sip.SipEvent; +import com.genersoft.iot.vmp.gb28181.service.IPlatformService; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract; -import com.genersoft.iot.vmp.gb28181.service.IPlatformService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo; import gov.nist.javax.sip.message.SIPResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -21,10 +21,10 @@ import javax.sip.header.WWWAuthenticateHeader; import javax.sip.message.Response; import java.text.ParseException; -/** +/** * @description:Register响应处理器 * @author: swwheihei - * @date: 2020年5月3日 下午5:32:23 + * @date: 2020年5月3日 下午5:32:23 */ @Slf4j @Component @@ -44,6 +44,9 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract { @Autowired private IPlatformService platformService; + @Autowired + private SipSubscribe sipSubscribe; + @Override public void afterPropertiesSet() throws Exception { // 添加消息处理的订阅 @@ -59,23 +62,19 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract { public void process(ResponseEvent evt) { SIPResponse response = (SIPResponse)evt.getResponse(); String callId = response.getCallIdHeader().getCallId(); - PlatformRegisterInfo platformRegisterInfo = redisCatchStorage.queryPlatformRegisterInfo(callId); - if (platformRegisterInfo == null) { - log.info(String.format("[国标级联]未找到callId: %s 的注册/注销平台id", callId )); + long seqNumber = response.getCSeqHeader().getSeqNumber(); + SipEvent subscribe = sipSubscribe.getSubscribe(callId + seqNumber); + if (subscribe == null || subscribe.getSipTransactionInfo() == null || subscribe.getSipTransactionInfo().getUser() == null) { return; } - PlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(platformRegisterInfo.getPlatformId()); - if (parentPlatformCatch == null) { - log.warn(String.format("[国标级联]收到注册/注销%S请求,平台:%s,但是平台缓存信息未查询到!!!", response.getStatusCode(),platformRegisterInfo.getPlatformId())); - return; - } + String action = subscribe.getSipTransactionInfo().getExpires() > 0 ? "注册" : "注销"; + String platFormServerGbId = subscribe.getSipTransactionInfo().getUser(); - String action = platformRegisterInfo.isRegister() ? "注册" : "注销"; - log.info(String.format("[国标级联]%s %S响应,%s ", action, response.getStatusCode(), platformRegisterInfo.getPlatformId() )); - Platform parentPlatform = parentPlatformCatch.getPlatform(); - if (parentPlatform == null) { - log.warn(String.format("[国标级联]收到 %s %s的%S请求, 但是平台信息未查询到!!!", platformRegisterInfo.getPlatformId(), action, response.getStatusCode())); + log.info("[国标级联]{} {}响应 {} ", action, response.getStatusCode(), platFormServerGbId); + Platform platform = platformService.queryPlatformByServerGBId(platFormServerGbId); + if (platform == null) { + log.warn("[国标级联]收到 来自{}的 {} 回复 {}, 但是平台信息未查询到!!!", platFormServerGbId, action, response.getStatusCode()); return; } @@ -83,21 +82,17 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract { WWWAuthenticateHeader www = (WWWAuthenticateHeader)response.getHeader(WWWAuthenticateHeader.NAME); SipTransactionInfo sipTransactionInfo = new SipTransactionInfo(response); try { - sipCommanderForPlatform.register(parentPlatform, sipTransactionInfo, www, null, null, platformRegisterInfo.isRegister()); + sipCommanderForPlatform.register(platform, sipTransactionInfo, www, null, null, subscribe.getSipTransactionInfo().getExpires() > 0); } catch (SipException | InvalidArgumentException | ParseException e) { log.error("[命令发送失败] 国标级联 再次注册: {}", e.getMessage()); } }else if (response.getStatusCode() == Response.OK){ - - if (platformRegisterInfo.isRegister()) { + if (subscribe.getSipTransactionInfo().getExpires() > 0) { SipTransactionInfo sipTransactionInfo = new SipTransactionInfo(response); - platformService.online(parentPlatform, sipTransactionInfo); + platformService.online(platform, sipTransactionInfo); }else { - platformService.offline(parentPlatform, true); + platformService.offline(platform); } - - // 注册/注销成功移除缓存的信息 - redisCatchStorage.delPlatformRegisterInfo(callId); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java index 0bce5f872..59c9ed722 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java @@ -1,7 +1,7 @@ package com.genersoft.iot.vmp.gb28181.utils; import com.genersoft.iot.vmp.gb28181.bean.Gb28181Sdp; -import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo; +import com.genersoft.iot.vmp.common.RemoteAddressInfo; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.utils.GitUtil; import gov.nist.javax.sip.address.AddressImpl; diff --git a/src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java b/src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java index 2660cb6a9..431eb29d8 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java +++ b/src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java @@ -3,9 +3,11 @@ package com.genersoft.iot.vmp.media.bean; import com.genersoft.iot.vmp.media.zlm.dto.ZLMServerConfig; import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; import org.springframework.util.ObjectUtils; @Schema(description = "流媒体服务信息") +@Data public class MediaServer { @Schema(description = "ID") @@ -135,268 +137,4 @@ public class MediaServer { transcodeSuffix = zlmServerConfig.getTranscodeSuffix(); } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getHookIp() { - return hookIp; - } - - public void setHookIp(String hookIp) { - this.hookIp = hookIp; - } - - public String getSdpIp() { - return sdpIp; - } - - public void setSdpIp(String sdpIp) { - this.sdpIp = sdpIp; - } - - public String getStreamIp() { - return streamIp; - } - - public void setStreamIp(String streamIp) { - this.streamIp = streamIp; - } - - public int getHttpPort() { - return httpPort; - } - - public void setHttpPort(int httpPort) { - this.httpPort = httpPort; - } - - public int getHttpSSlPort() { - return httpSSlPort; - } - - public void setHttpSSlPort(int httpSSlPort) { - this.httpSSlPort = httpSSlPort; - } - - public int getRtmpPort() { - return rtmpPort; - } - - public void setRtmpPort(int rtmpPort) { - this.rtmpPort = rtmpPort; - } - - public int getRtmpSSlPort() { - return rtmpSSlPort; - } - - public void setRtmpSSlPort(int rtmpSSlPort) { - this.rtmpSSlPort = rtmpSSlPort; - } - - public int getRtpProxyPort() { - return rtpProxyPort; - } - - public void setRtpProxyPort(int rtpProxyPort) { - this.rtpProxyPort = rtpProxyPort; - } - - public int getRtspPort() { - return rtspPort; - } - - public void setRtspPort(int rtspPort) { - this.rtspPort = rtspPort; - } - - public int getRtspSSLPort() { - return rtspSSLPort; - } - - public void setRtspSSLPort(int rtspSSLPort) { - this.rtspSSLPort = rtspSSLPort; - } - - public boolean isAutoConfig() { - return autoConfig; - } - - public void setAutoConfig(boolean autoConfig) { - this.autoConfig = autoConfig; - } - - public String getSecret() { - return secret; - } - - public void setSecret(String secret) { - this.secret = secret; - } - - public boolean isRtpEnable() { - return rtpEnable; - } - - public void setRtpEnable(boolean rtpEnable) { - this.rtpEnable = rtpEnable; - } - - public String getRtpPortRange() { - return rtpPortRange; - } - - public void setRtpPortRange(String rtpPortRange) { - this.rtpPortRange = rtpPortRange; - } - - public int getRecordAssistPort() { - return recordAssistPort; - } - - public void setRecordAssistPort(int recordAssistPort) { - this.recordAssistPort = recordAssistPort; - } - - public boolean isDefaultServer() { - return defaultServer; - } - - public void setDefaultServer(boolean defaultServer) { - this.defaultServer = defaultServer; - } - - public String getCreateTime() { - return createTime; - } - - public void setCreateTime(String createTime) { - this.createTime = createTime; - } - - public String getUpdateTime() { - return updateTime; - } - - public void setUpdateTime(String updateTime) { - this.updateTime = updateTime; - } - - public boolean isStatus() { - return status; - } - - public void setStatus(boolean status) { - this.status = status; - } - - public String getLastKeepaliveTime() { - return lastKeepaliveTime; - } - - public void setLastKeepaliveTime(String lastKeepaliveTime) { - this.lastKeepaliveTime = lastKeepaliveTime; - } - - public Float getHookAliveInterval() { - return hookAliveInterval; - } - - public void setHookAliveInterval(Float hookAliveInterval) { - this.hookAliveInterval = hookAliveInterval; - } - - public String getSendRtpPortRange() { - return sendRtpPortRange; - } - - public void setSendRtpPortRange(String sendRtpPortRange) { - this.sendRtpPortRange = sendRtpPortRange; - } - - public int getRecordDay() { - return recordDay; - } - - public void setRecordDay(int recordDay) { - this.recordDay = recordDay; - } - - public String getRecordPath() { - return recordPath; - } - - public void setRecordPath(String recordPath) { - this.recordPath = recordPath; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public int getFlvPort() { - return flvPort; - } - - public void setFlvPort(int flvPort) { - this.flvPort = flvPort; - } - - public int getFlvSSLPort() { - return flvSSLPort; - } - - public void setFlvSSLPort(int flvSSLPort) { - this.flvSSLPort = flvSSLPort; - } - - public int getWsFlvPort() { - return wsFlvPort; - } - - public void setWsFlvPort(int wsFlvPort) { - this.wsFlvPort = wsFlvPort; - } - - public int getWsFlvSSLPort() { - return wsFlvSSLPort; - } - - public void setWsFlvSSLPort(int wsFlvSSLPort) { - this.wsFlvSSLPort = wsFlvSSLPort; - } - - public String getTranscodeSuffix() { - return transcodeSuffix; - } - - public void setTranscodeSuffix(String transcodeSuffix) { - this.transcodeSuffix = transcodeSuffix; - } - - public String getServerId() { - return serverId; - } - - public void setServerId(String serverId) { - this.serverId = serverId; - } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java index 0a089cf2f..98f9c7518 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java @@ -794,7 +794,11 @@ public class MediaServerServiceImpl implements IMediaServerService { if (streamInfoList == null || streamInfoList.isEmpty()) { return null; }else { - return streamInfoList.get(0); + StreamInfo streamInfo = streamInfoList.get(0); + if (addr != null && !addr.isEmpty()) { + streamInfo.changeStreamIp(addr); + } + return streamInfo; } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java index 87aa801ea..b6a8b5fbd 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -103,7 +103,9 @@ public class ZLMHttpHookListener { String mediaServerId = json.getString("mediaServerId"); MediaServer mediaServer = mediaServerService.getOne(mediaServerId); if (mediaServer == null) { - return new HookResultForOnPublish(0, "success"); + HookResultForOnPublish fail = HookResultForOnPublish.Fail(); + log.warn("[ZLM HOOK]推流鉴权 响应:{}->找不到对应的mediaServer", param.getMediaServerId()); + return fail; } ResultForOnPublish resultForOnPublish = mediaService.authenticatePublish(mediaServer, param.getApp(), param.getStream(), param.getParams()); @@ -177,6 +179,9 @@ public class ZLMHttpHookListener { ret.put("code", 0); return ret; } + if (mediaInfo.getTranscodeSuffix() != null && param.getStream().endsWith(mediaInfo.getTranscodeSuffix())) { + param.setStream(param.getStream().substring(0, param.getStream().lastIndexOf(mediaInfo.getTranscodeSuffix()) - 1)); + } if (!ObjectUtils.isEmpty(mediaInfo.getTranscodeSuffix()) && !"null".equalsIgnoreCase(mediaInfo.getTranscodeSuffix()) && param.getStream().endsWith(mediaInfo.getTranscodeSuffix()) ) { diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java index 0edc415b1..0cdf62689 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java @@ -491,7 +491,7 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { if (data == null) { throw new ControllerException(jsonObject.getInteger("code"), "代理结果异常: " + jsonObject); }else { - streamProxy.setStreamKey(jsonObject.getString("key")); + streamProxy.setStreamKey(data.getString("key")); // 由于此时流未注册,手动拼装流信息 mediaInfo = new MediaInfo(); mediaInfo.setApp(streamProxy.getApp()); diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaServerStatusManager.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaServerStatusManager.java index 029e46ca8..37e6e846d 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaServerStatusManager.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaServerStatusManager.java @@ -186,7 +186,6 @@ public class ZLMMediaServerStatusManager { log.info("[ZLM-连接成功] ID:{}, 地址: {}:{}", mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort()); mediaServerItem.setStatus(true); mediaServerItem.setHookAliveInterval(10F); - mediaServerService.update(mediaServerItem); // 发送上线通知 eventPublisher.mediaServerOnlineEventPublish(mediaServerItem); if(mediaServerItem.isAutoConfig()) { @@ -243,6 +242,11 @@ public class ZLMMediaServerStatusManager { if (mediaServerItem.getWsFlvSSLPort() == 0) { mediaServerItem.setWsFlvSSLPort(zlmServerConfig.getHttpSSLport()); } + if (Objects.isNull(zlmServerConfig.getTranscodeSuffix())) { + mediaServerItem.setTranscodeSuffix(null); + }else { + mediaServerItem.setTranscodeSuffix(zlmServerConfig.getTranscodeSuffix()); + } mediaServerItem.setHookAliveInterval(10F); } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMServerConfig.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMServerConfig.java index 05fc57d0a..84ebc3e32 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMServerConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMServerConfig.java @@ -2,7 +2,11 @@ package com.genersoft.iot.vmp.media.zlm.dto; import com.alibaba.fastjson2.annotation.JSONField; import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; +import lombok.Data; +import lombok.EqualsAndHashCode; +@EqualsAndHashCode(callSuper = true) +@Data public class ZLMServerConfig extends HookParam { @JSONField(name = "api.apiDebug") @@ -334,892 +338,4 @@ public class ZLMServerConfig extends HookParam { @JSONField(name = "transcode.suffix") private String transcodeSuffix; - - public String getHookIp() { - return hookIp; - } - - public void setHookIp(String hookIp) { - this.hookIp = hookIp; - } - - public String getApiDebug() { - return apiDebug; - } - - public void setApiDebug(String apiDebug) { - this.apiDebug = apiDebug; - } - - public String getApiSecret() { - return apiSecret; - } - - public void setApiSecret(String apiSecret) { - this.apiSecret = apiSecret; - } - - public String getFfmpegBin() { - return ffmpegBin; - } - - public void setFfmpegBin(String ffmpegBin) { - this.ffmpegBin = ffmpegBin; - } - - public String getFfmpegCmd() { - return ffmpegCmd; - } - - public void setFfmpegCmd(String ffmpegCmd) { - this.ffmpegCmd = ffmpegCmd; - } - - public String getFfmpegLog() { - return ffmpegLog; - } - - public void setFfmpegLog(String ffmpegLog) { - this.ffmpegLog = ffmpegLog; - } - - public String getGeneralEnableVhost() { - return generalEnableVhost; - } - - public void setGeneralEnableVhost(String generalEnableVhost) { - this.generalEnableVhost = generalEnableVhost; - } - - public String getGeneralMediaServerId() { - return generalMediaServerId; - } - - public void setGeneralMediaServerId(String generalMediaServerId) { - this.generalMediaServerId = generalMediaServerId; - } - - public String getGeneralFlowThreshold() { - return generalFlowThreshold; - } - - public void setGeneralFlowThreshold(String generalFlowThreshold) { - this.generalFlowThreshold = generalFlowThreshold; - } - - public String getGeneralMaxStreamWaitMS() { - return generalMaxStreamWaitMS; - } - - public void setGeneralMaxStreamWaitMS(String generalMaxStreamWaitMS) { - this.generalMaxStreamWaitMS = generalMaxStreamWaitMS; - } - - public int getGeneralStreamNoneReaderDelayMS() { - return generalStreamNoneReaderDelayMS; - } - - public void setGeneralStreamNoneReaderDelayMS(int generalStreamNoneReaderDelayMS) { - this.generalStreamNoneReaderDelayMS = generalStreamNoneReaderDelayMS; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getSdpIp() { - return sdpIp; - } - - public void setSdpIp(String sdpIp) { - this.sdpIp = sdpIp; - } - - public String getStreamIp() { - return streamIp; - } - - public void setStreamIp(String streamIp) { - this.streamIp = streamIp; - } - - public String getUpdateTime() { - return updateTime; - } - - public void setUpdateTime(String updateTime) { - this.updateTime = updateTime; - } - - public String getCreateTime() { - return createTime; - } - - public void setCreateTime(String createTime) { - this.createTime = createTime; - } - - public String getHlsFileBufSize() { - return hlsFileBufSize; - } - - public void setHlsFileBufSize(String hlsFileBufSize) { - this.hlsFileBufSize = hlsFileBufSize; - } - - public String getHlsFilePath() { - return hlsFilePath; - } - - public void setHlsFilePath(String hlsFilePath) { - this.hlsFilePath = hlsFilePath; - } - - public String getHlsSegDur() { - return hlsSegDur; - } - - public void setHlsSegDur(String hlsSegDur) { - this.hlsSegDur = hlsSegDur; - } - - public String getHlsSegNum() { - return hlsSegNum; - } - - public void setHlsSegNum(String hlsSegNum) { - this.hlsSegNum = hlsSegNum; - } - - public String getHookAccessFileExceptHLS() { - return hookAccessFileExceptHLS; - } - - public void setHookAccessFileExceptHLS(String hookAccessFileExceptHLS) { - this.hookAccessFileExceptHLS = hookAccessFileExceptHLS; - } - - public String getHookAdminParams() { - return hookAdminParams; - } - - public void setHookAdminParams(String hookAdminParams) { - this.hookAdminParams = hookAdminParams; - } - - public String getHookEnable() { - return hookEnable; - } - - public void setHookEnable(String hookEnable) { - this.hookEnable = hookEnable; - } - - public String getHookOnFlowReport() { - return hookOnFlowReport; - } - - public void setHookOnFlowReport(String hookOnFlowReport) { - this.hookOnFlowReport = hookOnFlowReport; - } - - public String getHookOnHttpAccess() { - return hookOnHttpAccess; - } - - public void setHookOnHttpAccess(String hookOnHttpAccess) { - this.hookOnHttpAccess = hookOnHttpAccess; - } - - public String getHookOnPlay() { - return hookOnPlay; - } - - public void setHookOnPlay(String hookOnPlay) { - this.hookOnPlay = hookOnPlay; - } - - public String getHookOnPublish() { - return hookOnPublish; - } - - public void setHookOnPublish(String hookOnPublish) { - this.hookOnPublish = hookOnPublish; - } - - public String getHookOnRecordMp4() { - return hookOnRecordMp4; - } - - public void setHookOnRecordMp4(String hookOnRecordMp4) { - this.hookOnRecordMp4 = hookOnRecordMp4; - } - - public String getHookOnRtspAuth() { - return hookOnRtspAuth; - } - - public void setHookOnRtspAuth(String hookOnRtspAuth) { - this.hookOnRtspAuth = hookOnRtspAuth; - } - - public String getHookOnRtspRealm() { - return hookOnRtspRealm; - } - - public void setHookOnRtspRealm(String hookOnRtspRealm) { - this.hookOnRtspRealm = hookOnRtspRealm; - } - - public String getHookOnShellLogin() { - return hookOnShellLogin; - } - - public void setHookOnShellLogin(String hookOnShellLogin) { - this.hookOnShellLogin = hookOnShellLogin; - } - - public String getHookOnStreamChanged() { - return hookOnStreamChanged; - } - - public void setHookOnStreamChanged(String hookOnStreamChanged) { - this.hookOnStreamChanged = hookOnStreamChanged; - } - - public String getHookOnStreamNoneReader() { - return hookOnStreamNoneReader; - } - - public void setHookOnStreamNoneReader(String hookOnStreamNoneReader) { - this.hookOnStreamNoneReader = hookOnStreamNoneReader; - } - - public String getHookOnStreamNotFound() { - return hookOnStreamNotFound; - } - - public void setHookOnStreamNotFound(String hookOnStreamNotFound) { - this.hookOnStreamNotFound = hookOnStreamNotFound; - } - - public String getHookTimeoutSec() { - return hookTimeoutSec; - } - - public void setHookTimeoutSec(String hookTimeoutSec) { - this.hookTimeoutSec = hookTimeoutSec; - } - - public String getHttpCharSet() { - return httpCharSet; - } - - public void setHttpCharSet(String httpCharSet) { - this.httpCharSet = httpCharSet; - } - - public String getHttpKeepAliveSecond() { - return httpKeepAliveSecond; - } - - public void setHttpKeepAliveSecond(String httpKeepAliveSecond) { - this.httpKeepAliveSecond = httpKeepAliveSecond; - } - - public String getHttpMaxReqCount() { - return httpMaxReqCount; - } - - public void setHttpMaxReqCount(String httpMaxReqCount) { - this.httpMaxReqCount = httpMaxReqCount; - } - - public String getHttpMaxReqSize() { - return httpMaxReqSize; - } - - public void setHttpMaxReqSize(String httpMaxReqSize) { - this.httpMaxReqSize = httpMaxReqSize; - } - - public String getHttpNotFound() { - return httpNotFound; - } - - public void setHttpNotFound(String httpNotFound) { - this.httpNotFound = httpNotFound; - } - - public int getHttpPort() { - return httpPort; - } - - public void setHttpPort(int httpPort) { - this.httpPort = httpPort; - } - - public String getHttpRootPath() { - return httpRootPath; - } - - public void setHttpRootPath(String httpRootPath) { - this.httpRootPath = httpRootPath; - } - - public String getHttpSendBufSize() { - return httpSendBufSize; - } - - public void setHttpSendBufSize(String httpSendBufSize) { - this.httpSendBufSize = httpSendBufSize; - } - - public int getHttpSSLport() { - return httpSSLport; - } - - public void setHttpSSLport(int httpSSLport) { - this.httpSSLport = httpSSLport; - } - - public String getMulticastAddrMax() { - return multicastAddrMax; - } - - public void setMulticastAddrMax(String multicastAddrMax) { - this.multicastAddrMax = multicastAddrMax; - } - - public String getMulticastAddrMin() { - return multicastAddrMin; - } - - public void setMulticastAddrMin(String multicastAddrMin) { - this.multicastAddrMin = multicastAddrMin; - } - - public String getMulticastUdpTTL() { - return multicastUdpTTL; - } - - public void setMulticastUdpTTL(String multicastUdpTTL) { - this.multicastUdpTTL = multicastUdpTTL; - } - - public String getRecordAppName() { - return recordAppName; - } - - public void setRecordAppName(String recordAppName) { - this.recordAppName = recordAppName; - } - - public String getRecordFilePath() { - return recordFilePath; - } - - public void setRecordFilePath(String recordFilePath) { - this.recordFilePath = recordFilePath; - } - - public String getRecordFileSecond() { - return recordFileSecond; - } - - public void setRecordFileSecond(String recordFileSecond) { - this.recordFileSecond = recordFileSecond; - } - - public String getRecordFileSampleMS() { - return recordFileSampleMS; - } - - public void setRecordFileSampleMS(String recordFileSampleMS) { - this.recordFileSampleMS = recordFileSampleMS; - } - - public String getRtmpHandshakeSecond() { - return rtmpHandshakeSecond; - } - - public void setRtmpHandshakeSecond(String rtmpHandshakeSecond) { - this.rtmpHandshakeSecond = rtmpHandshakeSecond; - } - - public String getRtmpKeepAliveSecond() { - return rtmpKeepAliveSecond; - } - - public void setRtmpKeepAliveSecond(String rtmpKeepAliveSecond) { - this.rtmpKeepAliveSecond = rtmpKeepAliveSecond; - } - - public String getRtmpModifyStamp() { - return rtmpModifyStamp; - } - - public void setRtmpModifyStamp(String rtmpModifyStamp) { - this.rtmpModifyStamp = rtmpModifyStamp; - } - - public int getRtmpPort() { - return rtmpPort; - } - - public void setRtmpPort(int rtmpPort) { - this.rtmpPort = rtmpPort; - } - - public int getRtmpSslPort() { - return rtmpSslPort; - } - - public void setRtmpSslPort(int rtmpSslPort) { - this.rtmpSslPort = rtmpSslPort; - } - - public String getRtpAudioMtuSize() { - return rtpAudioMtuSize; - } - - public void setRtpAudioMtuSize(String rtpAudioMtuSize) { - this.rtpAudioMtuSize = rtpAudioMtuSize; - } - - public String getRtpClearCount() { - return rtpClearCount; - } - - public void setRtpClearCount(String rtpClearCount) { - this.rtpClearCount = rtpClearCount; - } - - public String getRtpCycleMS() { - return rtpCycleMS; - } - - public void setRtpCycleMS(String rtpCycleMS) { - this.rtpCycleMS = rtpCycleMS; - } - - public String getRtpMaxRtpCount() { - return rtpMaxRtpCount; - } - - public void setRtpMaxRtpCount(String rtpMaxRtpCount) { - this.rtpMaxRtpCount = rtpMaxRtpCount; - } - - public String getRtpVideoMtuSize() { - return rtpVideoMtuSize; - } - - public void setRtpVideoMtuSize(String rtpVideoMtuSize) { - this.rtpVideoMtuSize = rtpVideoMtuSize; - } - - public String getRtpProxyCheckSource() { - return rtpProxyCheckSource; - } - - public void setRtpProxyCheckSource(String rtpProxyCheckSource) { - this.rtpProxyCheckSource = rtpProxyCheckSource; - } - - public String getRtpProxyDumpDir() { - return rtpProxyDumpDir; - } - - public void setRtpProxyDumpDir(String rtpProxyDumpDir) { - this.rtpProxyDumpDir = rtpProxyDumpDir; - } - - public int getRtpProxyPort() { - return rtpProxyPort; - } - - public void setRtpProxyPort(int rtpProxyPort) { - this.rtpProxyPort = rtpProxyPort; - } - - public String getRtpProxyTimeoutSec() { - return rtpProxyTimeoutSec; - } - - public void setRtpProxyTimeoutSec(String rtpProxyTimeoutSec) { - this.rtpProxyTimeoutSec = rtpProxyTimeoutSec; - } - - public String getRtspAuthBasic() { - return rtspAuthBasic; - } - - public void setRtspAuthBasic(String rtspAuthBasic) { - this.rtspAuthBasic = rtspAuthBasic; - } - - public String getRtspHandshakeSecond() { - return rtspHandshakeSecond; - } - - public void setRtspHandshakeSecond(String rtspHandshakeSecond) { - this.rtspHandshakeSecond = rtspHandshakeSecond; - } - - public String getRtspKeepAliveSecond() { - return rtspKeepAliveSecond; - } - - public void setRtspKeepAliveSecond(String rtspKeepAliveSecond) { - this.rtspKeepAliveSecond = rtspKeepAliveSecond; - } - - public int getRtspPort() { - return rtspPort; - } - - public void setRtspPort(int rtspPort) { - this.rtspPort = rtspPort; - } - - public int getRtspSSlport() { - return rtspSSlport; - } - - public void setRtspSSlport(int rtspSSlport) { - this.rtspSSlport = rtspSSlport; - } - - public String getShellMaxReqSize() { - return shellMaxReqSize; - } - - public void setShellMaxReqSize(String shellMaxReqSize) { - this.shellMaxReqSize = shellMaxReqSize; - } - - public String getShellPhell() { - return shellPhell; - } - - public void setShellPhell(String shellPhell) { - this.shellPhell = shellPhell; - } - - public Float getHookAliveInterval() { - return hookAliveInterval; - } - - public void setHookAliveInterval(Float hookAliveInterval) { - this.hookAliveInterval = hookAliveInterval; - } - - public String getPortRange() { - return portRange; - } - - public void setPortRange(String portRange) { - this.portRange = portRange; - } - - public String getApiSnapRoot() { - return apiSnapRoot; - } - - public void setApiSnapRoot(String apiSnapRoot) { - this.apiSnapRoot = apiSnapRoot; - } - - public String getApiDefaultSnap() { - return apiDefaultSnap; - } - - public void setApiDefaultSnap(String apiDefaultSnap) { - this.apiDefaultSnap = apiDefaultSnap; - } - - public String getFfmpegSnap() { - return ffmpegSnap; - } - - public void setFfmpegSnap(String ffmpegSnap) { - this.ffmpegSnap = ffmpegSnap; - } - - public String getFfmpegRestartSec() { - return ffmpegRestartSec; - } - - public void setFfmpegRestartSec(String ffmpegRestartSec) { - this.ffmpegRestartSec = ffmpegRestartSec; - } - - public String getProtocolModifyStamp() { - return protocolModifyStamp; - } - - public void setProtocolModifyStamp(String protocolModifyStamp) { - this.protocolModifyStamp = protocolModifyStamp; - } - - public String getProtocolEnableAudio() { - return protocolEnableAudio; - } - - public void setProtocolEnableAudio(String protocolEnableAudio) { - this.protocolEnableAudio = protocolEnableAudio; - } - - public String getProtocolAddMuteAudio() { - return protocolAddMuteAudio; - } - - public void setProtocolAddMuteAudio(String protocolAddMuteAudio) { - this.protocolAddMuteAudio = protocolAddMuteAudio; - } - - public String getProtocolContinuePushMs() { - return protocolContinuePushMs; - } - - public void setProtocolContinuePushMs(String protocolContinuePushMs) { - this.protocolContinuePushMs = protocolContinuePushMs; - } - - public String getProtocolEnableHls() { - return protocolEnableHls; - } - - public void setProtocolEnableHls(String protocolEnableHls) { - this.protocolEnableHls = protocolEnableHls; - } - - public String getProtocolEnableMp4() { - return protocolEnableMp4; - } - - public void setProtocolEnableMp4(String protocolEnableMp4) { - this.protocolEnableMp4 = protocolEnableMp4; - } - - public String getProtocolEnableRtsp() { - return protocolEnableRtsp; - } - - public void setProtocolEnableRtsp(String protocolEnableRtsp) { - this.protocolEnableRtsp = protocolEnableRtsp; - } - - public String getProtocolEnableRtmp() { - return protocolEnableRtmp; - } - - public void setProtocolEnableRtmp(String protocolEnableRtmp) { - this.protocolEnableRtmp = protocolEnableRtmp; - } - - public String getProtocolEnableTs() { - return protocolEnableTs; - } - - public void setProtocolEnableTs(String protocolEnableTs) { - this.protocolEnableTs = protocolEnableTs; - } - - public String getProtocolEnableFmp4() { - return protocolEnableFmp4; - } - - public void setProtocolEnableFmp4(String protocolEnableFmp4) { - this.protocolEnableFmp4 = protocolEnableFmp4; - } - - public String getProtocolMp4AsPlayer() { - return protocolMp4AsPlayer; - } - - public void setProtocolMp4AsPlayer(String protocolMp4AsPlayer) { - this.protocolMp4AsPlayer = protocolMp4AsPlayer; - } - - public String getProtocolMp4MaxSecond() { - return protocolMp4MaxSecond; - } - - public void setProtocolMp4MaxSecond(String protocolMp4MaxSecond) { - this.protocolMp4MaxSecond = protocolMp4MaxSecond; - } - - public String getProtocolMp4SavePath() { - return protocolMp4SavePath; - } - - public void setProtocolMp4SavePath(String protocolMp4SavePath) { - this.protocolMp4SavePath = protocolMp4SavePath; - } - - public String getProtocolHlsSavePath() { - return protocolHlsSavePath; - } - - public void setProtocolHlsSavePath(String protocolHlsSavePath) { - this.protocolHlsSavePath = protocolHlsSavePath; - } - - public String getProtocolHlsDemand() { - return protocolHlsDemand; - } - - public void setProtocolHlsDemand(String protocolHlsDemand) { - this.protocolHlsDemand = protocolHlsDemand; - } - - public String getProtocolRtspDemand() { - return protocolRtspDemand; - } - - public void setProtocolRtspDemand(String protocolRtspDemand) { - this.protocolRtspDemand = protocolRtspDemand; - } - - public String getProtocolRtmpDemand() { - return protocolRtmpDemand; - } - - public void setProtocolRtmpDemand(String protocolRtmpDemand) { - this.protocolRtmpDemand = protocolRtmpDemand; - } - - public String getProtocolTsDemand() { - return protocolTsDemand; - } - - public void setProtocolTsDemand(String protocolTsDemand) { - this.protocolTsDemand = protocolTsDemand; - } - - public String getProtocolFmp4Demand() { - return protocolFmp4Demand; - } - - public void setProtocolFmp4Demand(String protocolFmp4Demand) { - this.protocolFmp4Demand = protocolFmp4Demand; - } - - public String getGeneralResetWhenRePlay() { - return generalResetWhenRePlay; - } - - public void setGeneralResetWhenRePlay(String generalResetWhenRePlay) { - this.generalResetWhenRePlay = generalResetWhenRePlay; - } - - public String getGeneralMergeWriteMS() { - return generalMergeWriteMS; - } - - public void setGeneralMergeWriteMS(String generalMergeWriteMS) { - this.generalMergeWriteMS = generalMergeWriteMS; - } - - public String getGeneralWaitTrackReadyMs() { - return generalWaitTrackReadyMs; - } - - public void setGeneralWaitTrackReadyMs(String generalWaitTrackReadyMs) { - this.generalWaitTrackReadyMs = generalWaitTrackReadyMs; - } - - public String getGeneralWaitAddTrackMs() { - return generalWaitAddTrackMs; - } - - public void setGeneralWaitAddTrackMs(String generalWaitAddTrackMs) { - this.generalWaitAddTrackMs = generalWaitAddTrackMs; - } - - public String getGeneralUnreadyFrameCache() { - return generalUnreadyFrameCache; - } - - public void setGeneralUnreadyFrameCache(String generalUnreadyFrameCache) { - this.generalUnreadyFrameCache = generalUnreadyFrameCache; - } - - public String getHlsSegRetain() { - return hlsSegRetain; - } - - public void setHlsSegRetain(String hlsSegRetain) { - this.hlsSegRetain = hlsSegRetain; - } - - public String getHlsBroadcastRecordTs() { - return hlsBroadcastRecordTs; - } - - public void setHlsBroadcastRecordTs(String hlsBroadcastRecordTs) { - this.hlsBroadcastRecordTs = hlsBroadcastRecordTs; - } - - public String getHlsDeleteDelaySec() { - return hlsDeleteDelaySec; - } - - public void setHlsDeleteDelaySec(String hlsDeleteDelaySec) { - this.hlsDeleteDelaySec = hlsDeleteDelaySec; - } - - public String getHlsSegKeep() { - return hlsSegKeep; - } - - public void setHlsSegKeep(String hlsSegKeep) { - this.hlsSegKeep = hlsSegKeep; - } - - public String getHookOnServerStarted() { - return hookOnServerStarted; - } - - public void setHookOnServerStarted(String hookOnServerStarted) { - this.hookOnServerStarted = hookOnServerStarted; - } - - public String getHookOnServerKeepalive() { - return hookOnServerKeepalive; - } - - public void setHookOnServerKeepalive(String hookOnServerKeepalive) { - this.hookOnServerKeepalive = hookOnServerKeepalive; - } - - public String getHookOnSendRtpStopped() { - return hookOnSendRtpStopped; - } - - public void setHookOnSendRtpStopped(String hookOnSendRtpStopped) { - this.hookOnSendRtpStopped = hookOnSendRtpStopped; - } - - public String getHookOnRtpServerTimeout() { - return hookOnRtpServerTimeout; - } - - public void setHookOnRtpServerTimeout(String hookOnRtpServerTimeout) { - this.hookOnRtpServerTimeout = hookOnRtpServerTimeout; - } - - public String getTranscodeSuffix() { - return transcodeSuffix; - } - - public void setTranscodeSuffix(String transcodeSuffix) { - this.transcodeSuffix = transcodeSuffix; - } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/GPSMsgInfo.java b/src/main/java/com/genersoft/iot/vmp/service/bean/GPSMsgInfo.java index 7156985c6..fca4751d3 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/bean/GPSMsgInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/service/bean/GPSMsgInfo.java @@ -30,7 +30,7 @@ public class GPSMsgInfo { /** * 速度,单位:km/h (可选) */ - private double speed; + private Double speed; /** * 产生通知时间, 时间格式: 2020-01-14T14:32:12 @@ -40,23 +40,23 @@ public class GPSMsgInfo { /** * 方向,取值为当前摄像头方向与正北方的顺时针夹角,取值范围0°~360°,单位:(°)(可选) */ - private String direction; + private Double direction; /** * 海拔高度,单位:m(可选) */ - private String altitude; + private Double altitude; private boolean stored; public static GPSMsgInfo getInstance(MobilePosition mobilePosition) { GPSMsgInfo gpsMsgInfo = new GPSMsgInfo(); gpsMsgInfo.setChannelId(mobilePosition.getChannelId()); - gpsMsgInfo.setAltitude(mobilePosition.getAltitude() + ""); + gpsMsgInfo.setAltitude(mobilePosition.getAltitude()); gpsMsgInfo.setLng(mobilePosition.getLongitude()); gpsMsgInfo.setLat(mobilePosition.getLatitude()); gpsMsgInfo.setSpeed(mobilePosition.getSpeed()); - gpsMsgInfo.setDirection(mobilePosition.getDirection() + ""); + gpsMsgInfo.setDirection(mobilePosition.getDirection()); gpsMsgInfo.setTime(DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); return gpsMsgInfo; } diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/IRedisRpcPlayService.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/IRedisRpcPlayService.java index 174fa6b67..db1035e3e 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/IRedisRpcPlayService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/IRedisRpcPlayService.java @@ -26,7 +26,7 @@ public interface IRedisRpcPlayService { String frontEndCommand(String serverId, Integer channelId, int cmdCode, int parameter1, int parameter2, int combindCode2); - void playPush(Integer id, ErrorCallback callback); + void playPush(String serverId, Integer id, ErrorCallback callback); StreamInfo playProxy(String serverId, int id); diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java index 886cd88eb..f524a9218 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; import com.genersoft.iot.vmp.gb28181.bean.Platform; import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService; import com.genersoft.iot.vmp.gb28181.service.IDeviceService; +import com.genersoft.iot.vmp.gb28181.service.IPlatformChannelService; import com.genersoft.iot.vmp.gb28181.service.IPlatformService; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; @@ -55,6 +56,9 @@ public class RedisAlarmMsgListener implements MessageListener { @Autowired private IPlatformService platformService; + @Autowired + private IPlatformChannelService platformChannelService; + private final ConcurrentLinkedQueue taskQueue = new ConcurrentLinkedQueue<>(); @Autowired @@ -89,11 +93,11 @@ public class RedisAlarmMsgListener implements MessageListener { log.warn("[REDIS的ALARM通知]消息解析失败"); continue; } - String gbId = alarmChannelMessage.getGbId(); + String chanelId = alarmChannelMessage.getGbId(); DeviceAlarm deviceAlarm = new DeviceAlarm(); deviceAlarm.setCreateTime(DateUtil.getNow()); - deviceAlarm.setChannelId(gbId); + deviceAlarm.setChannelId(chanelId); deviceAlarm.setAlarmDescription(alarmChannelMessage.getAlarmDescription()); deviceAlarm.setAlarmMethod("" + alarmChannelMessage.getAlarmSn()); deviceAlarm.setAlarmType("" + alarmChannelMessage.getAlarmType()); @@ -102,7 +106,7 @@ public class RedisAlarmMsgListener implements MessageListener { deviceAlarm.setLongitude(0); deviceAlarm.setLatitude(0); - if (ObjectUtils.isEmpty(gbId)) { + if (ObjectUtils.isEmpty(chanelId)) { if (userSetting.getSendToPlatformsWhenIdLost()) { // 发送给所有的上级 List parentPlatforms = platformService.queryEnablePlatformList(userSetting.getServerId()); @@ -129,7 +133,6 @@ public class RedisAlarmMsgListener implements MessageListener { } } } - } // 获取开启了消息推送的设备和平台 List devices = channelService.queryDeviceWithAsMessageChannel(); @@ -143,24 +146,28 @@ public class RedisAlarmMsgListener implements MessageListener { } } } - } else { - Device device = deviceService.getDeviceByDeviceId(gbId); - Platform platform = platformService.queryPlatformByServerGBId(gbId); - if (device != null && platform == null) { + // 获取该通道ID是属于设备还是对应的上级平台 + Device device = deviceService.getDeviceBySourceChannelDeviceId(chanelId); + List platforms = platformChannelService.queryByPlatformBySharChannelId(chanelId); + if (device != null && device.getServerId().equals(userSetting.getServerId()) && (platforms == null || platforms.isEmpty())) { try { commander.sendAlarmMessage(device, deviceAlarm); } catch (InvalidArgumentException | SipException | ParseException e) { log.error("[命令发送失败] 发送报警: {}", e.getMessage()); } - } else if (device == null && platform != null) { - try { - commanderForPlatform.sendAlarmMessage(platform, deviceAlarm); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 发送报警: {}", e.getMessage()); + } else if (device == null && (platforms != null && !platforms.isEmpty() )) { + for (Platform platform : platforms) { + if (platform.getServerId().equals(userSetting.getServerId())) { + try { + commanderForPlatform.sendAlarmMessage(platform, deviceAlarm); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 发送报警: {}", e.getMessage()); + } + } } } else { - log.warn("无法确定" + gbId + "是平台还是设备"); + log.warn("[REDIS的ALARM通知] 未查询到" + chanelId + "所属的平台或设备"); } } } catch (Exception e) { diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGpsMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGpsMsgListener.java index bd34dd6f6..0c19ab986 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGpsMsgListener.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGpsMsgListener.java @@ -1,9 +1,11 @@ package com.genersoft.iot.vmp.service.redisMsg; import com.alibaba.fastjson2.JSON; +import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.streamPush.service.IStreamPushService; +import com.genersoft.iot.vmp.utils.DateUtil; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; @@ -15,9 +17,11 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; /** - * 接收来自redis的GPS更新通知, 此处只针对推流设备 + * 接收来自redis的GPS更新通知 * * @author lin * 监听: SUBSCRIBE VM_MSG_GPS @@ -33,6 +37,9 @@ public class RedisGpsMsgListener implements MessageListener { @Autowired private IStreamPushService streamPushService; + @Autowired + private IGbChannelService channelService; + private final ConcurrentLinkedQueue taskQueue = new ConcurrentLinkedQueue<>(); @@ -42,7 +49,7 @@ public class RedisGpsMsgListener implements MessageListener { taskQueue.offer(message); } - @Scheduled(fixedDelay = 200) //每400毫秒执行一次 + @Scheduled(fixedDelay = 200, timeUnit = TimeUnit.MILLISECONDS) //每400毫秒执行一次 public void executeTaskQueue() { if (taskQueue.isEmpty()) { return; @@ -61,6 +68,7 @@ public class RedisGpsMsgListener implements MessageListener { for (Message msg : messageDataList) { try { GPSMsgInfo gpsMsgInfo = JSON.parseObject(msg.getBody(), GPSMsgInfo.class); + gpsMsgInfo.setTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(gpsMsgInfo.getTime())); log.info("[REDIS的位置变化通知], {}", JSON.toJSONString(gpsMsgInfo)); // 只是放入redis缓存起来 redisCatchStorage.updateGpsMsgInfo(gpsMsgInfo); @@ -74,15 +82,18 @@ public class RedisGpsMsgListener implements MessageListener { /** * 定时将经纬度更新到数据库 */ - @Scheduled(fixedDelay = 2 * 1000) //每2秒执行一次 + @Scheduled(fixedDelay = 2, timeUnit = TimeUnit.SECONDS) //每2秒执行一次 public void execute() { // 需要查询到 List gpsMsgInfoList = redisCatchStorage.getAllGpsMsgInfo(); if (!gpsMsgInfoList.isEmpty()) { - streamPushService.updateGPSFromGPSMsgInfo(gpsMsgInfoList); - for (GPSMsgInfo msgInfo : gpsMsgInfoList) { - msgInfo.setStored(true); - redisCatchStorage.updateGpsMsgInfo(msgInfo); + gpsMsgInfoList = gpsMsgInfoList.stream().filter(gpsMsgInfo -> !gpsMsgInfo.isStored()).collect(Collectors.toList());; + if (!gpsMsgInfoList.isEmpty()) { + channelService.updateGPSFromGPSMsgInfo(gpsMsgInfoList); + for (GPSMsgInfo msgInfo : gpsMsgInfoList) { + msgInfo.setStored(true); + redisCatchStorage.updateGpsMsgInfo(msgInfo); + } } } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusMsgListener.java index 6f1b3d109..e3d4e9670 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusMsgListener.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusMsgListener.java @@ -48,7 +48,7 @@ public class RedisPushStreamStatusMsgListener implements MessageListener, Applic @Override public void onMessage(Message message, byte[] bytes) { - log.info("[REDIS: 流设备状态变化]: {}", new String(message.getBody())); + log.info("[REDIS: 推流设备状态变化]: {}", new String(message.getBody())); taskQueue.offer(message); } @@ -84,15 +84,17 @@ public class RedisPushStreamStatusMsgListener implements MessageListener, Applic if (streamStatusMessage.getOfflineStreams() != null && !streamStatusMessage.getOfflineStreams().isEmpty()) { // 更新部分设备离线 + log.info("[REDIS: 推流设备状态变化] 更新部分设备离线: {}个", streamStatusMessage.getOfflineStreams().size()); streamPushService.offline(streamStatusMessage.getOfflineStreams()); } if (streamStatusMessage.getOnlineStreams() != null && !streamStatusMessage.getOnlineStreams().isEmpty()) { // 更新部分设备上线 + log.info("[REDIS: 推流设备状态变化] 更新部分设备上线: {}个", streamStatusMessage.getOnlineStreams().size()); streamPushService.online(streamStatusMessage.getOnlineStreams()); } } catch (Exception e) { - log.warn("[REDIS消息-推流设备状态变化] 发现未处理的异常, \r\n{}", JSON.toJSONString(msg)); + log.warn("[REDIS消息-推流设备状态变化] 发现未处理的异常, \r\n{}", JSON.parseObject(msg.getBody())); log.error("[REDIS消息-推流设备状态变化] 异常内容: ", e); } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcPlatformController.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcPlatformController.java index c5a9f4604..cf037934d 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcPlatformController.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcPlatformController.java @@ -9,7 +9,6 @@ import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.Platform; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; -import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; import com.genersoft.iot.vmp.gb28181.service.IPlatformChannelService; import com.genersoft.iot.vmp.gb28181.service.IPlatformService; import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcController; @@ -72,6 +71,7 @@ public class RedisRpcPlatformController extends RpcController { public RedisRpcResponse catalogEventPublish(RedisRpcRequest request) { JSONObject jsonObject = JSONObject.parseObject(request.getParam().toString()); Platform platform = jsonObject.getObject("platform", Platform.class); + List channels = jsonObject.getJSONArray("channels").toJavaList(CommonGBChannel.class); String type = jsonObject.getString("type"); eventPublisher.catalogEventPublish(platform, channels, type, false); diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcStreamPushController.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcStreamPushController.java index d9fd90ed2..53212b178 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcStreamPushController.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcStreamPushController.java @@ -181,7 +181,8 @@ public class RedisRpcStreamPushController extends RpcController { */ @RedisRpcMapping("play") public RedisRpcResponse play(RedisRpcRequest request) { - int id = Integer.parseInt(request.getParam().toString()); + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + int id = paramJson.getInteger("id"); RedisRpcResponse response = request.getResponse(); if (id <= 0) { response.setStatusCode(ErrorCode.ERROR400.getCode()); diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcPlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcPlayServiceImpl.java index 4404a7205..5f369efaf 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcPlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcPlayServiceImpl.java @@ -193,8 +193,11 @@ public class RedisRpcPlayServiceImpl implements IRedisRpcPlayService { } @Override - public void playPush(Integer id, ErrorCallback callback) { - RedisRpcRequest request = buildRequest("streamPush/play", id); + public void playPush(String serverId, Integer id, ErrorCallback callback) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("id", id); + RedisRpcRequest request = buildRequest("streamPush/play", jsonObject); + request.setToId(serverId); RedisRpcResponse response = redisRpcConfig.request(request, userSetting.getPlayTimeout(), TimeUnit.SECONDS); if (response == null) { callback.run(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg(), null); diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcServiceImpl.java index b2d65963c..531ef6aaf 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcServiceImpl.java @@ -231,6 +231,9 @@ public class RedisRpcServiceImpl implements IRedisRpcService { RedisRpcRequest request = buildRequest("platform/update", platform); request.setToId(serverId); RedisRpcResponse response = redisRpcConfig.request(request, 40, TimeUnit.MILLISECONDS); + if(response == null) { + return false; + } return Boolean.parseBoolean(response.getBody().toString()); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java index 1f05a7b48..106cf3aea 100755 --- a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java @@ -9,7 +9,6 @@ import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; -import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo; import java.util.List; import java.util.Map; @@ -23,23 +22,13 @@ public interface IRedisCatchStorage { */ Long getCSEQ(); - void updatePlatformCatchInfo(PlatformCatch parentPlatformCatch); - - PlatformCatch queryPlatformCatchInfo(String platformGbId); - - void delPlatformCatchInfo(String platformGbId); - - void updatePlatformRegisterInfo(String callId, PlatformRegisterInfo platformRegisterInfo); - - PlatformRegisterInfo queryPlatformRegisterInfo(String callId); - - void delPlatformRegisterInfo(String callId); - /** * 在redis添加wvp的信息 */ void updateWVPInfo(ServerInfo serverInfo, int time); + void removeOfflineWVPInfo(String serverId); + /** * 发送推流生成与推流消失消息 * @param jsonObject 消息内容 diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java index 8682461fe..f440d57c9 100755 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java @@ -81,7 +81,7 @@ public interface MediaServerMapper { @Update(value = {" ") - List getListFromRedis(List offlineStreams); + List getListInList(List offlineStreams); @Select("SELECT CONCAT(app,stream) from wvp_stream_push") diff --git a/src/main/java/com/genersoft/iot/vmp/streamPush/service/IStreamPushService.java b/src/main/java/com/genersoft/iot/vmp/streamPush/service/IStreamPushService.java index 54143b385..9621d8c9e 100755 --- a/src/main/java/com/genersoft/iot/vmp/streamPush/service/IStreamPushService.java +++ b/src/main/java/com/genersoft/iot/vmp/streamPush/service/IStreamPushService.java @@ -1,7 +1,6 @@ package com.genersoft.iot.vmp.streamPush.service; import com.genersoft.iot.vmp.media.bean.MediaServer; -import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; import com.genersoft.iot.vmp.streamPush.bean.StreamPush; import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; @@ -98,5 +97,4 @@ public interface IStreamPushService { void batchRemove(Set ids); - void updateGPSFromGPSMsgInfo(List gpsMsgInfoList); } diff --git a/src/main/java/com/genersoft/iot/vmp/streamPush/service/impl/StreamPushPlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/streamPush/service/impl/StreamPushPlayServiceImpl.java index 6f44f36e8..d8adfa3f0 100644 --- a/src/main/java/com/genersoft/iot/vmp/streamPush/service/impl/StreamPushPlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/streamPush/service/impl/StreamPushPlayServiceImpl.java @@ -39,7 +39,7 @@ public class StreamPushPlayServiceImpl implements IStreamPushPlayService { @Autowired private UserSetting userSetting; - + @Autowired private DynamicTask dynamicTask; @@ -57,27 +57,28 @@ public class StreamPushPlayServiceImpl implements IStreamPushPlayService { StreamPush streamPush = streamPushMapper.queryOne(id); Assert.notNull(streamPush, "推流信息未找到"); - if (!userSetting.getServerId().equals(streamPush.getServerId())) { - redisRpcPlayService.playPush(id, callback); + if (streamPush.isPushing() && !userSetting.getServerId().equals(streamPush.getServerId())) { + redisRpcPlayService.playPush(streamPush.getServerId(), id, callback); return; } MediaServer mediaServer = mediaServerService.getOne(streamPush.getMediaServerId()); - Assert.notNull(mediaServer, "节点" + streamPush.getMediaServerId() + "未找到"); - MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, streamPush.getApp(), streamPush.getStream()); - if (mediaInfo != null) { - String callId = null; - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(streamPush.getApp(), streamPush.getStream()); - if (streamAuthorityInfo != null) { - callId = streamAuthorityInfo.getCallId(); + if (mediaServer != null) { + MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, streamPush.getApp(), streamPush.getStream()); + if (mediaInfo != null) { + String callId = null; + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(streamPush.getApp(), streamPush.getStream()); + if (streamAuthorityInfo != null) { + callId = streamAuthorityInfo.getCallId(); + } + callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), mediaServerService.getStreamInfoByAppAndStream(mediaServer, + streamPush.getApp(), streamPush.getStream(), mediaInfo, callId)); + if (!streamPush.isPushing()) { + streamPush.setPushing(true); + streamPushMapper.update(streamPush); + } + return; } - callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), mediaServerService.getStreamInfoByAppAndStream(mediaServer, - streamPush.getApp(), streamPush.getStream(), mediaInfo, callId)); - if (!streamPush.isPushing()) { - streamPush.setPushing(true); - streamPushMapper.update(streamPush); - } - return; } Assert.isTrue(streamPush.isStartOfflinePush(), "通道未推流"); // 发送redis消息以使设备上线,流上线后被 diff --git a/src/main/java/com/genersoft/iot/vmp/streamPush/service/impl/StreamPushServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/streamPush/service/impl/StreamPushServiceImpl.java index acfb564ab..1090d3c58 100755 --- a/src/main/java/com/genersoft/iot/vmp/streamPush/service/impl/StreamPushServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/streamPush/service/impl/StreamPushServiceImpl.java @@ -16,7 +16,6 @@ import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.media.zlm.dto.hook.OriginType; import com.genersoft.iot.vmp.service.ISendRtpServerService; -import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.streamPush.bean.StreamPush; @@ -52,6 +51,7 @@ public class StreamPushServiceImpl implements IStreamPushService { private UserSetting userSetting; @Autowired + private IMediaServerService mediaServerService; @Autowired @@ -124,25 +124,21 @@ public class StreamPushServiceImpl implements IStreamPushService { public void onApplicationEvent(MediaDepartureEvent event) { // 兼容流注销时类型从redis记录获取 - MediaInfo mediaInfo = redisCatchStorage.getStreamInfo( - event.getApp(), event.getStream(), event.getMediaServer().getId()); + MediaInfo mediaInfo = redisCatchStorage.getPushListItem(event.getApp(), event.getStream()); + if (mediaInfo != null) { + log.info("[推流信息] 查询到redis存在推流缓存, 开始清理,{}/{}", event.getApp(), event.getStream()); String type = OriginType.values()[mediaInfo.getOriginType()].getType(); - redisCatchStorage.removeStream(event.getMediaServer().getId(), type, event.getApp(), event.getStream()); - if ("PUSH".equalsIgnoreCase(type)) { - // 冗余数据,自己系统中自用 - redisCatchStorage.removePushListItem(event.getApp(), event.getStream(), event.getMediaServer().getId()); - } - if (type != null) { - // 发送流变化redis消息 - JSONObject jsonObject = new JSONObject(); - jsonObject.put("serverId", userSetting.getServerId()); - jsonObject.put("app", event.getApp()); - jsonObject.put("stream", event.getStream()); - jsonObject.put("register", false); - jsonObject.put("mediaServerId", event.getMediaServer().getId()); - redisCatchStorage.sendStreamChangeMsg(type, jsonObject); - } + // 冗余数据,自己系统中自用 + redisCatchStorage.removePushListItem(event.getApp(), event.getStream(), event.getMediaServer().getId()); + // 发送流变化redis消息 + JSONObject jsonObject = new JSONObject(); + jsonObject.put("serverId", userSetting.getServerId()); + jsonObject.put("app", event.getApp()); + jsonObject.put("stream", event.getStream()); + jsonObject.put("register", false); + jsonObject.put("mediaServerId", event.getMediaServer().getId()); + redisCatchStorage.sendStreamChangeMsg(type, jsonObject); } StreamPush streamPush = getPush(event.getApp(), event.getStream()); if (streamPush == null) { @@ -462,15 +458,29 @@ public class StreamPushServiceImpl implements IStreamPushService { @Override public void offline(List offlineStreams) { // 更新部分设备离线 - List streamPushList = streamPushMapper.getListFromRedis(offlineStreams); + List streamPushList = streamPushMapper.getListInList(offlineStreams); + if (streamPushList.isEmpty()) { + log.info("[推流设备] 设备离线操作未发现可操作数据。"); + return; + } List commonGBChannelList = gbChannelService.queryListByStreamPushList(streamPushList); gbChannelService.offline(commonGBChannelList); } @Override public void online(List onlineStreams) { + if (onlineStreams.isEmpty()) { + log.info("[设备上线] 推流设备列表为空"); + return; + } // 更新部分设备上线streamPushService - List streamPushList = streamPushMapper.getListFromRedis(onlineStreams); + List streamPushList = streamPushMapper.getListInList(onlineStreams); + if (streamPushList.isEmpty()) { + for (StreamPushItemFromRedis onlineStream : onlineStreams) { + log.info("[设备上线] 未查询到这些通道: {}/{}", onlineStream.getApp(), onlineStream.getStream()); + } + return; + } List commonGBChannelList = gbChannelService.queryListByStreamPushList(streamPushList); gbChannelService.online(commonGBChannelList); } @@ -574,26 +584,13 @@ public class StreamPushServiceImpl implements IStreamPushService { if (streamPushList.isEmpty()) { return; } - List commonGBChannelList = new ArrayList<>(); + Set channelIds = new HashSet<>(); streamPushList.stream().forEach(streamPush -> { if (streamPush.getGbDeviceId() != null) { - commonGBChannelList.add(streamPush.buildCommonGBChannel()); + channelIds.add(streamPush.getGbId()); } }); streamPushMapper.batchDel(streamPushList); - gbChannelService.delete(ids); - } - - @Override - public void updateGPSFromGPSMsgInfo(List gpsMsgInfoList) { - List channels = new ArrayList<>(); - for (GPSMsgInfo gpsMsgInfo : gpsMsgInfoList) { - CommonGBChannel channel = new CommonGBChannel(); - channel.setGbDeviceId(gpsMsgInfo.getId()); - channel.setGbLongitude(gpsMsgInfo.getLng()); - channel.setGbLatitude(gpsMsgInfo.getLat()); - channels.add(channel); - } - gbChannelService.updateGpsByDeviceIdForStreamPush(channels); + gbChannelService.delete(channelIds); } } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java index 07c3b3cbd..c3080051e 100755 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java @@ -55,7 +55,12 @@ public class CloudRecordController { @Parameter(name = "year", description = "年,置空则查询当年", required = false) @Parameter(name = "month", description = "月,置空则查询当月", required = false) @Parameter(name = "mediaServerId", description = "流媒体ID,置空则查询全部", required = false) - public List openRtpServer(@RequestParam(required = true) String app, @RequestParam(required = true) String stream, @RequestParam(required = false) Integer year, @RequestParam(required = false) Integer month, @RequestParam(required = false) String mediaServerId + public List openRtpServer( + @RequestParam(required = true) String app, + @RequestParam(required = true) String stream, + @RequestParam(required = false) Integer year, + @RequestParam(required = false) Integer month, + @RequestParam(required = false) String mediaServerId ) { log.info("[云端录像] 查询存在云端录像的日期 app->{}, stream->{}, mediaServerId->{}, year->{}, month->{}", app, stream, mediaServerId, year, month); @@ -96,7 +101,15 @@ public class CloudRecordController { @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = false) @Parameter(name = "mediaServerId", description = "流媒体ID,置空则查询全部流媒体", required = false) @Parameter(name = "callId", description = "每次录像的唯一标识,置空则查询全部流媒体", required = false) - public PageInfo openRtpServer(@RequestParam(required = false) String query, @RequestParam(required = false) String app, @RequestParam(required = false) String stream, @RequestParam int page, @RequestParam int count, @RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime, @RequestParam(required = false) String mediaServerId, @RequestParam(required = false) String callId + public PageInfo openRtpServer(@RequestParam(required = false) String query, + @RequestParam(required = false) String app, + @RequestParam(required = false) String stream, + @RequestParam int page, + @RequestParam int count, + @RequestParam(required = false) String startTime, + @RequestParam(required = false) String endTime, + @RequestParam(required = false) String mediaServerId, + @RequestParam(required = false) String callId ) { log.info("[云端录像] 查询 app->{}, stream->{}, mediaServerId->{}, page->{}, count->{}, startTime->{}, endTime->{}, callId->{}", app, stream, mediaServerId, page, count, startTime, endTime, callId); diff --git a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiControlController.java b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiControlController.java index edfd71a2d..fcb7f70d2 100644 --- a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiControlController.java +++ b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiControlController.java @@ -37,10 +37,9 @@ public class ApiControlController { * @param channel 通道序号 * @param code 通道编号 * @param speed 速度(0~255) 默认值: 129 - * @return */ @GetMapping(value = "/ptz") - private void list(String serial,String command, + private void ptz(String serial,String command, @RequestParam(required = false)Integer channel, @RequestParam(required = false)String code, @RequestParam(required = false)Integer speed){ @@ -55,7 +54,7 @@ public class ApiControlController { if (device == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "device[ " + serial + " ]未找到"); } - int cmdCode = 0; + int cmdCode = -1; switch (command){ case "left": cmdCode = 2; @@ -93,6 +92,9 @@ public class ApiControlController { default: break; } + if (cmdCode == -1) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未识别的指令:" + command); + } // 默认值 50 try { cmder.frontEndCmd(device, code, cmdCode, speed, speed, speed); @@ -110,7 +112,6 @@ public class ApiControlController { * @param command 控制指令 允许值: set, goto, remove * @param preset 预置位编号(1~255) * @param name 预置位名称, command=set 时有效 - * @return */ @GetMapping(value = "/preset") private void list(String serial,String command, diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 80de5efb4..2164909c6 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -2,4 +2,4 @@ spring: application: name: wvp profiles: - active: dev \ No newline at end of file + active: 273 diff --git a/src/main/resources/配置详情.yml b/src/main/resources/配置详情.yml index a501da9e7..dd76aa9e6 100644 --- a/src/main/resources/配置详情.yml +++ b/src/main/resources/配置详情.yml @@ -249,6 +249,8 @@ user-settings: jwk-file: classpath:jwk.json # wvp集群模式下如果注册向上级的wvp奔溃,则自动选择一个其他wvp继续注册到上级 auto-register-platform: true + # 按需发送位置, 默认发送移动位置订阅时如果位置不变则不发送, 设置为false按照国标间隔持续发送 + send-position-on-demand: true # 关闭在线文档(生产环境建议关闭) springdoc: diff --git a/web_src/src/components/DeviceList.vue b/web_src/src/components/DeviceList.vue index 67b6eba08..f994f9bf1 100755 --- a/web_src/src/components/DeviceList.vue +++ b/web_src/src/components/DeviceList.vue @@ -167,7 +167,7 @@ export default { }, mounted() { this.initData(); - this.updateLooper = setInterval(this.initData, 10000); + this.updateLooper = setInterval(this.getDeviceList, 10000); }, destroyed() { this.$destroy('videojs'); diff --git a/web_src/src/components/channelList.vue b/web_src/src/components/channelList.vue index f20ad566f..f314a5f19 100755 --- a/web_src/src/components/channelList.vue +++ b/web_src/src/components/channelList.vue @@ -65,7 +65,7 @@ - + @@ -96,6 +96,7 @@ import uiHeader from '../layout/UiHeader.vue' import DeviceService from "./service/DeviceService"; import GroupTree from "./common/GroupTree.vue"; import GbChannelSelect from "./dialog/GbChannelSelect.vue"; +import UnusualGroupChannelSelect from "./dialog/UnusualGroupChannelSelect.vue"; import RegionTree from "./common/RegionTree.vue"; export default { @@ -103,6 +104,7 @@ export default { components: { RegionTree, GbChannelSelect, + UnusualGroupChannelSelect, uiHeader, GroupTree, }, @@ -323,6 +325,9 @@ export default { onChannelChange: function (deviceId) { // }, + showUnusualChanel: function () { + this.$refs.unusualGroupChannelSelect.openDialog() + }, } }; diff --git a/web_src/src/components/region.vue b/web_src/src/components/region.vue index 8482eb9b9..1ae6f29b0 100755 --- a/web_src/src/components/region.vue +++ b/web_src/src/components/region.vue @@ -28,12 +28,11 @@ 类型: + - - - + 添加通道 @@ -62,9 +61,7 @@ diff --git a/web_src/src/main.js b/web_src/src/main.js index f37a2dcc6..7ce9b40f7 100755 --- a/web_src/src/main.js +++ b/web_src/src/main.js @@ -76,21 +76,34 @@ axios.interceptors.request.use( Vue.prototype.$axios = axios; Vue.prototype.$cookies.config(60 * 30); Vue.prototype.$tableHeght = window.innerHeight - 170; +Vue.prototype.$channelTypeList = { + 1: {id: 1, name: "国标设备", style: {color: "#409eff", borderColor: "#b3d8ff"}}, + 2: {id: 2, name: "推流设备", style: {color: "#67c23a", borderColor: "#c2e7b0"}}, + 3: {id: 3, name: "拉流代理", style: {color: "#e6a23c", borderColor: "#f5dab1"}}, +}; + + new Vue({ beforeCreate: function () { // 获取本平台的服务ID - axios({ - method: 'get', - url: `/api/server/system/configInfo`, - }).then( (res)=> { - if (res.data.code === 0) { - Vue.prototype.$myServerId = res.data.data.addOn.serverId; - } - }).catch( (error)=> { - }); + console.log("获取本平台的服务ID") + if (!this.$myServerId) { + axios({ + method: 'get', + url: `/api/server/system/configInfo`, + }).then( (res)=> { + if (res.data.code === 0) { + console.log(res.data) + console.log("当前服务ID: " + res.data.data.addOn.serverId) + Vue.prototype.$myServerId = res.data.data.addOn.serverId; + } + }).catch( (error)=> { + }); + } + }, router: router, render: h => h(App), diff --git a/web_src/static/js/ZLMRTCClient.js b/web_src/static/js/ZLMRTCClient.js index 30a08eff6..bbb4c4a87 100644 --- a/web_src/static/js/ZLMRTCClient.js +++ b/web_src/static/js/ZLMRTCClient.js @@ -6560,7 +6560,7 @@ var ZLMRTCClient = (function (exports) { resolve(response); } else { reject(new AxiosError_1( - 'Request failed with status code ' + response.status, + '请求失败, 状态码:' + response.status, [AxiosError_1.ERR_BAD_REQUEST, AxiosError_1.ERR_BAD_RESPONSE][Math.floor(response.status / 100) - 4], response.config, response.request, @@ -7885,7 +7885,7 @@ var ZLMRTCClient = (function (exports) { }).then(response => { let ret = response.data; //JSON.parse(response.data); if (ret.code != 0) { - // mean failed for offer/anwser exchange + // mean failed for offer/anwser exchange this.dispatch(Events$1.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, ret); return; } @@ -7989,7 +7989,7 @@ var ZLMRTCClient = (function (exports) { }).then(response => { let ret = response.data; //JSON.parse(response.data); if (ret.code != 0) { - // mean failed for offer/anwser exchange + // mean failed for offer/anwser exchange this.dispatch(Events$1.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, ret); return; } diff --git a/数据库/2.7.3/初始化-mysql-2.7.3.sql b/数据库/2.7.3/初始化-mysql-2.7.3.sql index c3f5eee7c..284c2d712 100644 --- a/数据库/2.7.3/初始化-mysql-2.7.3.sql +++ b/数据库/2.7.3/初始化-mysql-2.7.3.sql @@ -1,5 +1,6 @@ /*建表*/ -create table wvp_device +drop table IF EXISTS wvp_device; +create table IF NOT EXISTS wvp_device ( id serial primary key, device_id character varying(50) not null, @@ -39,7 +40,8 @@ create table wvp_device constraint uk_device_device unique (device_id) ); -create table wvp_device_alarm +drop table IF EXISTS wvp_device_alarm; +create table IF NOT EXISTS wvp_device_alarm ( id serial primary key, device_id character varying(50) not null, @@ -54,7 +56,8 @@ create table wvp_device_alarm create_time character varying(50) not null ); -create table wvp_device_mobile_position +drop table IF EXISTS wvp_device_mobile_position; +create table IF NOT EXISTS wvp_device_mobile_position ( id serial primary key, device_id character varying(50) not null, @@ -70,7 +73,8 @@ create table wvp_device_mobile_position create_time character varying(50) ); -create table wvp_device_channel +drop table IF EXISTS wvp_device_channel; +create table IF NOT EXISTS wvp_device_channel ( id serial primary key, device_id character varying(50), @@ -152,10 +156,16 @@ create table wvp_device_channel record_plan_id integer, data_type integer not null, data_device_id integer not null, + gps_speed double precision, + gps_altitude double precision, + gps_direction double precision, + index (data_type), + index (data_device_id), constraint uk_wvp_unique_channel unique (gb_device_id) ); -create table wvp_media_server +drop table IF EXISTS wvp_media_server; +create table IF NOT EXISTS wvp_media_server ( id character varying(255) primary key, ip character varying(50), @@ -191,7 +201,8 @@ create table wvp_media_server constraint uk_media_server_unique_ip_http_port unique (ip, http_port, server_id) ); -create table wvp_platform +drop table IF EXISTS wvp_platform; +create table IF NOT EXISTS wvp_platform ( id serial primary key, enable bool default false, @@ -231,8 +242,8 @@ create table wvp_platform constraint uk_platform_unique_server_gb_id unique (server_gb_id) ); - -create table wvp_platform_channel +drop table IF EXISTS wvp_platform_channel; +create table IF NOT EXISTS wvp_platform_channel ( id serial primary key, platform_id integer, @@ -275,7 +286,8 @@ create table wvp_platform_channel constraint uk_platform_gb_channel_device_id unique (custom_device_id) ); -create table wvp_platform_group +drop table IF EXISTS wvp_platform_group; +create table IF NOT EXISTS wvp_platform_group ( id serial primary key, platform_id integer, @@ -283,7 +295,8 @@ create table wvp_platform_group constraint uk_wvp_platform_group_platform_id_group_id unique (platform_id, group_id) ); -create table wvp_platform_region +drop table IF EXISTS wvp_platform_region; +create table IF NOT EXISTS wvp_platform_region ( id serial primary key, platform_id integer, @@ -291,7 +304,8 @@ create table wvp_platform_region constraint uk_wvp_platform_region_platform_id_group_id unique (platform_id, region_id) ); -create table wvp_stream_proxy +drop table IF EXISTS wvp_stream_proxy; +create table IF NOT EXISTS wvp_stream_proxy ( id serial primary key, type character varying(50), @@ -317,7 +331,8 @@ create table wvp_stream_proxy constraint uk_stream_proxy_app_stream unique (app, stream) ); -create table wvp_stream_push +drop table IF EXISTS wvp_stream_push; +create table IF NOT EXISTS wvp_stream_push ( id serial primary key, app character varying(255), @@ -333,7 +348,9 @@ create table wvp_stream_push start_offline_push bool default true, constraint uk_stream_push_app_stream unique (app, stream) ); -create table wvp_cloud_record + +drop table IF EXISTS wvp_cloud_record; +create table IF NOT EXISTS wvp_cloud_record ( id serial primary key, app character varying(255), @@ -351,7 +368,8 @@ create table wvp_cloud_record time_len bigint ); -create table wvp_user +drop table IF EXISTS wvp_user; +create table IF NOT EXISTS wvp_user ( id serial primary key, username character varying(255), @@ -363,7 +381,8 @@ create table wvp_user constraint uk_user_username unique (username) ); -create table wvp_user_role +drop table IF EXISTS wvp_user_role; +create table IF NOT EXISTS wvp_user_role ( id serial primary key, name character varying(50), @@ -371,18 +390,10 @@ create table wvp_user_role create_time character varying(50), update_time character varying(50) ); -create table wvp_resources_tree -( - id serial primary key, - is_catalog bool default true, - device_channel_id integer, - gb_stream_id integer, - name character varying(255), - parentId integer, - path character varying(255) -); -create table wvp_user_api_key + +drop table IF EXISTS wvp_user_api_key; +create table IF NOT EXISTS wvp_user_api_key ( id serial primary key, user_id bigint, @@ -403,7 +414,8 @@ VALUES (1, 'admin', '21232f297a57a5a743894a0e4a801fc3', 1, '2021-04-13 14:14:57' INSERT INTO wvp_user_role VALUES (1, 'admin', '0', '2021-04-13 14:14:57', '2021-04-13 14:14:57'); -CREATE TABLE wvp_common_group +drop table IF EXISTS wvp_common_group; +create table IF NOT EXISTS wvp_common_group ( id serial primary key, device_id varchar(50) NOT NULL, @@ -417,7 +429,8 @@ CREATE TABLE wvp_common_group constraint uk_common_group_device_platform unique (device_id) ); -CREATE TABLE wvp_common_region +drop table IF EXISTS wvp_common_region; +create table IF NOT EXISTS wvp_common_region ( id serial primary key, device_id varchar(50) NOT NULL, @@ -429,7 +442,8 @@ CREATE TABLE wvp_common_region constraint uk_common_region_device_id unique (device_id) ); -create table wvp_record_plan +drop table IF EXISTS wvp_record_plan; +create table IF NOT EXISTS wvp_record_plan ( id serial primary key, snap bool default false, @@ -438,7 +452,8 @@ create table wvp_record_plan update_time character varying(50) ); -create table wvp_record_plan_item +drop table IF EXISTS wvp_record_plan_item; +create table IF NOT EXISTS wvp_record_plan_item ( id serial primary key, start int, diff --git a/数据库/2.7.3/初始化-postgresql-kingbase-2.7.3.sql b/数据库/2.7.3/初始化-postgresql-kingbase-2.7.3.sql index 1d96dba0a..3423d0a49 100644 --- a/数据库/2.7.3/初始化-postgresql-kingbase-2.7.3.sql +++ b/数据库/2.7.3/初始化-postgresql-kingbase-2.7.3.sql @@ -1,5 +1,6 @@ /*建表*/ -create table wvp_device +drop table IF EXISTS wvp_device; +create table IF NOT EXISTS wvp_device ( id serial primary key, device_id character varying(50) not null, @@ -25,7 +26,7 @@ create table wvp_device charset character varying(50), ssrc_check bool default false, geo_coord_sys character varying(50), - media_server_id character varying(50), + media_server_id character varying(50) default 'auto', custom_name character varying(255), sdp_ip character varying(50), local_ip character varying(50), @@ -39,7 +40,8 @@ create table wvp_device constraint uk_device_device unique (device_id) ); -create table wvp_device_alarm +drop table IF EXISTS wvp_device_alarm; +create table IF NOT EXISTS wvp_device_alarm ( id serial primary key, device_id character varying(50) not null, @@ -54,7 +56,8 @@ create table wvp_device_alarm create_time character varying(50) not null ); -create table wvp_device_mobile_position +drop table IF EXISTS wvp_device_mobile_position; +create table IF NOT EXISTS wvp_device_mobile_position ( id serial primary key, device_id character varying(50) not null, @@ -70,7 +73,8 @@ create table wvp_device_mobile_position create_time character varying(50) ); -create table wvp_device_channel +drop table IF EXISTS wvp_device_channel; +create table IF NOT EXISTS wvp_device_channel ( id serial primary key, device_id character varying(50), @@ -152,10 +156,17 @@ create table wvp_device_channel record_plan_id integer, data_type integer not null, data_device_id integer not null, + gps_speed double precision, + gps_altitude double precision, + gps_direction double precision, constraint uk_wvp_unique_channel unique (gb_device_id) ); -create table wvp_media_server +CREATE INDEX idx_data_type ON wvp_device_channel (data_type); +CREATE INDEX idx_data_device_id ON wvp_device_channel (data_device_id); + +drop table IF EXISTS wvp_media_server; +create table IF NOT EXISTS wvp_media_server ( id character varying(255) primary key, ip character varying(50), @@ -191,7 +202,8 @@ create table wvp_media_server constraint uk_media_server_unique_ip_http_port unique (ip, http_port, server_id) ); -create table wvp_platform +drop table IF EXISTS wvp_platform; +create table IF NOT EXISTS wvp_platform ( id serial primary key, enable bool default false, @@ -231,8 +243,8 @@ create table wvp_platform constraint uk_platform_unique_server_gb_id unique (server_gb_id) ); - -create table wvp_platform_channel +drop table IF EXISTS wvp_platform_channel; +create table IF NOT EXISTS wvp_platform_channel ( id serial primary key, platform_id integer, @@ -275,7 +287,8 @@ create table wvp_platform_channel constraint uk_platform_gb_channel_device_id unique (custom_device_id) ); -create table wvp_platform_group +drop table IF EXISTS wvp_platform_group; +create table IF NOT EXISTS wvp_platform_group ( id serial primary key, platform_id integer, @@ -283,7 +296,8 @@ create table wvp_platform_group constraint uk_wvp_platform_group_platform_id_group_id unique (platform_id, group_id) ); -create table wvp_platform_region +drop table IF EXISTS wvp_platform_region; +create table IF NOT EXISTS wvp_platform_region ( id serial primary key, platform_id integer, @@ -291,7 +305,8 @@ create table wvp_platform_region constraint uk_wvp_platform_region_platform_id_group_id unique (platform_id, region_id) ); -create table wvp_stream_proxy +drop table IF EXISTS wvp_stream_proxy; +create table IF NOT EXISTS wvp_stream_proxy ( id serial primary key, type character varying(50), @@ -317,7 +332,8 @@ create table wvp_stream_proxy constraint uk_stream_proxy_app_stream unique (app, stream) ); -create table wvp_stream_push +drop table IF EXISTS wvp_stream_push; +create table IF NOT EXISTS wvp_stream_push ( id serial primary key, app character varying(255), @@ -333,7 +349,9 @@ create table wvp_stream_push start_offline_push bool default true, constraint uk_stream_push_app_stream unique (app, stream) ); -create table wvp_cloud_record + +drop table IF EXISTS wvp_cloud_record; +create table IF NOT EXISTS wvp_cloud_record ( id serial primary key, app character varying(255), @@ -348,11 +366,11 @@ create table wvp_cloud_record file_path character varying(500), collect bool default false, file_size int8, - time_len int8, - constraint uk_stream_push_app_stream_path unique (app, stream, file_path) + time_len int8 ); -create table wvp_user +drop table IF EXISTS wvp_user; +create table IF NOT EXISTS wvp_user ( id serial primary key, username character varying(255), @@ -364,7 +382,8 @@ create table wvp_user constraint uk_user_username unique (username) ); -create table wvp_user_role +drop table IF EXISTS wvp_user_role; +create table IF NOT EXISTS wvp_user_role ( id serial primary key, name character varying(50), @@ -372,18 +391,10 @@ create table wvp_user_role create_time character varying(50), update_time character varying(50) ); -create table wvp_resources_tree -( - id serial primary key, - is_catalog bool default true, - device_channel_id integer, - gb_stream_id integer, - name character varying(255), - parentId integer, - path character varying(255) -); -create table wvp_user_api_key + +drop table IF EXISTS wvp_user_api_key; +create table IF NOT EXISTS wvp_user_api_key ( id serial primary key, user_id int8, @@ -404,7 +415,8 @@ VALUES (1, 'admin', '21232f297a57a5a743894a0e4a801fc3', 1, '2021-04-13 14:14:57' INSERT INTO wvp_user_role VALUES (1, 'admin', '0', '2021-04-13 14:14:57', '2021-04-13 14:14:57'); -CREATE TABLE wvp_common_group +drop table IF EXISTS wvp_common_group; +create table IF NOT EXISTS wvp_common_group ( id serial primary key, device_id varchar(50) NOT NULL, @@ -418,7 +430,8 @@ CREATE TABLE wvp_common_group constraint uk_common_group_device_platform unique (device_id) ); -CREATE TABLE wvp_common_region +drop table IF EXISTS wvp_common_region; +create table IF NOT EXISTS wvp_common_region ( id serial primary key, device_id varchar(50) NOT NULL, @@ -430,7 +443,8 @@ CREATE TABLE wvp_common_region constraint uk_common_region_device_id unique (device_id) ); -create table wvp_record_plan +drop table IF EXISTS wvp_record_plan; +create table IF NOT EXISTS wvp_record_plan ( id serial primary key, snap bool default false, @@ -439,7 +453,8 @@ create table wvp_record_plan update_time character varying(50) ); -create table wvp_record_plan_item +drop table IF EXISTS wvp_record_plan_item; +create table IF NOT EXISTS wvp_record_plan_item ( id serial primary key, "start" int, diff --git a/数据库/2.7.3/数据库统合-更新.sql b/数据库/2.7.3/数据库统合-更新.sql deleted file mode 100644 index 8d850262e..000000000 --- a/数据库/2.7.3/数据库统合-更新.sql +++ /dev/null @@ -1,13 +0,0 @@ -/* -* WVP RPC 调用 -*/ -alter table wvp_device add server_id character varying(50); -alter table wvp_media_server add server_id character varying(50); -alter table wvp_stream_proxy add server_id character varying(50); -alter table wvp_cloud_record add server_id character varying(50); -alter table wvp_platform add server_id character varying(50); - -update wvp_device set server_id = "你服务的ID"; -update wvp_media_server set server_id = "你服务的ID"; -update wvp_stream_proxy set server_id = "你服务的ID"; -update wvp_cloud_record set server_id = "你服务的ID"; \ No newline at end of file diff --git a/数据库/2.7.3/更新-mysql-2.7.1升级到2.7.3.sql b/数据库/2.7.3/更新-mysql-2.7.1升级到2.7.3.sql new file mode 100644 index 000000000..da2d0f6e2 --- /dev/null +++ b/数据库/2.7.3/更新-mysql-2.7.1升级到2.7.3.sql @@ -0,0 +1,428 @@ + +drop table if exists wvp_resources_tree; +drop table if exists wvp_platform_catalog; +drop table if exists wvp_platform_gb_stream; +drop table if exists wvp_platform_gb_channel; +drop table if exists wvp_gb_stream; +drop table if exists wvp_log; +drop table IF EXISTS wvp_device; +drop table IF EXISTS wvp_platform; +drop table IF EXISTS wvp_media_server; +drop table IF EXISTS wvp_device_mobile_position; +drop table IF EXISTS wvp_device_channel; +drop table IF EXISTS wvp_stream_proxy; +drop table IF EXISTS wvp_stream_push; + +create table IF NOT EXISTS wvp_device +( + id serial primary key, + device_id character varying(50) not null, + name character varying(255), + manufacturer character varying(255), + model character varying(255), + firmware character varying(255), + transport character varying(50), + stream_mode character varying(50), + on_line bool default false, + register_time character varying(50), + keepalive_time character varying(50), + ip character varying(50), + create_time character varying(50), + update_time character varying(50), + port integer, + expires integer, + subscribe_cycle_for_catalog integer DEFAULT 0, + subscribe_cycle_for_mobile_position integer DEFAULT 0, + mobile_position_submission_interval integer DEFAULT 5, + subscribe_cycle_for_alarm integer DEFAULT 0, + host_address character varying(50), + charset character varying(50), + ssrc_check bool default false, + geo_coord_sys character varying(50), + media_server_id character varying(50) default 'auto', + custom_name character varying(255), + sdp_ip character varying(50), + local_ip character varying(50), + password character varying(255), + as_message_channel bool default false, + heart_beat_interval integer, + heart_beat_count integer, + position_capability integer, + broadcast_push_after_ack bool default false, + server_id character varying(50), + constraint uk_device_device unique (device_id) +); + +create table if not exists wvp_common_group +( + id bigint unsigned auto_increment primary key, + device_id varchar(50) not null, + name varchar(255) not null, + parent_id int null, + parent_device_id varchar(50) null, + business_group varchar(50) not null, + create_time varchar(50) not null, + update_time varchar(50) not null, + civil_code varchar(50) null, + constraint id + unique (id), + constraint uk_common_group_device_platform + unique (device_id) +); + +create table if not exists wvp_common_region +( + id bigint unsigned auto_increment + primary key, + device_id varchar(50) not null, + name varchar(255) not null, + parent_id int null, + parent_device_id varchar(50) null, + create_time varchar(50) not null, + update_time varchar(50) not null, + constraint id + unique (id), + constraint uk_common_region_device_id + unique (device_id) +); + +create table IF NOT EXISTS wvp_device_channel +( + id serial primary key, + device_id character varying(50), + name character varying(255), + manufacturer character varying(50), + model character varying(50), + owner character varying(50), + civil_code character varying(50), + block character varying(50), + address character varying(50), + parental integer, + parent_id character varying(50), + safety_way integer, + register_way integer, + cert_num character varying(50), + certifiable integer, + err_code integer, + end_time character varying(50), + secrecy integer, + ip_address character varying(50), + port integer, + password character varying(255), + status character varying(50), + longitude double precision, + latitude double precision, + ptz_type integer, + position_type integer, + room_type integer, + use_type integer, + supply_light_type integer, + direction_type integer, + resolution character varying(255), + business_group_id character varying(255), + download_speed character varying(255), + svc_space_support_mod integer, + svc_time_support_mode integer, + create_time character varying(50) not null, + update_time character varying(50) not null, + sub_count integer, + stream_id character varying(255), + has_audio bool default false, + gps_time character varying(50), + stream_identification character varying(50), + channel_type int default 0 not null, + gb_device_id character varying(50), + gb_name character varying(255), + gb_manufacturer character varying(255), + gb_model character varying(255), + gb_owner character varying(255), + gb_civil_code character varying(255), + gb_block character varying(255), + gb_address character varying(255), + gb_parental integer, + gb_parent_id character varying(255), + gb_safety_way integer, + gb_register_way integer, + gb_cert_num character varying(50), + gb_certifiable integer, + gb_err_code integer, + gb_end_time character varying(50), + gb_secrecy integer, + gb_ip_address character varying(50), + gb_port integer, + gb_password character varying(50), + gb_status character varying(50), + gb_longitude double, + gb_latitude double, + gb_business_group_id character varying(50), + gb_ptz_type integer, + gb_position_type integer, + gb_room_type integer, + gb_use_type integer, + gb_supply_light_type integer, + gb_direction_type integer, + gb_resolution character varying(255), + gb_download_speed character varying(255), + gb_svc_space_support_mod integer, + gb_svc_time_support_mode integer, + record_plan_id integer, + data_type integer not null, + data_device_id integer not null, + gps_speed double precision, + gps_altitude double precision, + gps_direction double precision, + index (data_type), + index (data_device_id), + constraint uk_wvp_unique_channel unique (gb_device_id) +); + +create table IF NOT EXISTS wvp_device_mobile_position +( + id serial primary key, + device_id character varying(50) not null, + channel_id character varying(50) not null, + device_name character varying(255), + time character varying(50), + longitude double precision, + latitude double precision, + altitude double precision, + speed double precision, + direction double precision, + report_source character varying(50), + create_time character varying(50) +); + +create table IF NOT EXISTS wvp_media_server +( + id character varying(255) primary key, + ip character varying(50), + hook_ip character varying(50), + sdp_ip character varying(50), + stream_ip character varying(50), + http_port integer, + http_ssl_port integer, + rtmp_port integer, + rtmp_ssl_port integer, + rtp_proxy_port integer, + rtsp_port integer, + rtsp_ssl_port integer, + flv_port integer, + flv_ssl_port integer, + ws_flv_port integer, + ws_flv_ssl_port integer, + auto_config bool default false, + secret character varying(50), + type character varying(50) default 'zlm', + rtp_enable bool default false, + rtp_port_range character varying(50), + send_rtp_port_range character varying(50), + record_assist_port integer, + default_server bool default false, + create_time character varying(50), + update_time character varying(50), + hook_alive_interval integer, + record_path character varying(255), + record_day integer default 7, + transcode_suffix character varying(255), + server_id character varying(50), + constraint uk_media_server_unique_ip_http_port unique (ip, http_port, server_id) +); + +create table IF NOT EXISTS wvp_platform +( + id serial primary key, + enable bool default false, + name character varying(255), + server_gb_id character varying(50), + server_gb_domain character varying(50), + server_ip character varying(50), + server_port integer, + device_gb_id character varying(50), + device_ip character varying(50), + device_port character varying(50), + username character varying(255), + password character varying(50), + expires character varying(50), + keep_timeout character varying(50), + transport character varying(50), + civil_code character varying(50), + manufacturer character varying(255), + model character varying(255), + address character varying(255), + character_set character varying(50), + ptz bool default false, + rtcp bool default false, + status bool default false, + catalog_group integer, + register_way integer, + secrecy integer, + create_time character varying(50), + update_time character varying(50), + as_message_channel bool default false, + catalog_with_platform integer default 1, + catalog_with_group integer default 1, + catalog_with_region integer default 1, + auto_push_channel bool default true, + send_stream_ip character varying(50), + server_id character varying(50), + constraint uk_platform_unique_server_gb_id unique (server_gb_id) +); + +create table IF NOT EXISTS wvp_stream_proxy +( + id serial primary key, + type character varying(50), + app character varying(255), + stream character varying(255), + src_url character varying(255), + timeout integer, + ffmpeg_cmd_key character varying(255), + rtsp_type character varying(50), + media_server_id character varying(50), + enable_audio bool default false, + enable_mp4 bool default false, + pulling bool default false, + enable bool default false, + enable_remove_none_reader bool default false, + create_time character varying(50), + name character varying(255), + update_time character varying(50), + stream_key character varying(255), + server_id character varying(50), + enable_disable_none_reader bool default false, + relates_media_server_id character varying(50), + constraint uk_stream_proxy_app_stream unique (app, stream) +); + +create table IF NOT EXISTS wvp_stream_push +( + id serial primary key, + app character varying(255), + stream character varying(255), + create_time character varying(50), + media_server_id character varying(50), + server_id character varying(50), + push_time character varying(50), + status bool default false, + update_time character varying(50), + pushing bool default false, + self bool default false, + start_offline_push bool default true, + constraint uk_stream_push_app_stream unique (app, stream) +); + +create table IF NOT EXISTS wvp_platform_channel +( + id serial primary key, + platform_id integer, + device_channel_id integer, + custom_device_id character varying(50), + custom_name character varying(255), + custom_manufacturer character varying(50), + custom_model character varying(50), + custom_owner character varying(50), + custom_civil_code character varying(50), + custom_block character varying(50), + custom_address character varying(50), + custom_parental integer, + custom_parent_id character varying(50), + custom_safety_way integer, + custom_register_way integer, + custom_cert_num character varying(50), + custom_certifiable integer, + custom_err_code integer, + custom_end_time character varying(50), + custom_secrecy integer, + custom_ip_address character varying(50), + custom_port integer, + custom_password character varying(255), + custom_status character varying(50), + custom_longitude double precision, + custom_latitude double precision, + custom_ptz_type integer, + custom_position_type integer, + custom_room_type integer, + custom_use_type integer, + custom_supply_light_type integer, + custom_direction_type integer, + custom_resolution character varying(255), + custom_business_group_id character varying(255), + custom_download_speed character varying(255), + custom_svc_space_support_mod integer, + custom_svc_time_support_mode integer, + constraint uk_platform_gb_channel_platform_id_catalog_id_device_channel_id unique (platform_id, device_channel_id), + constraint uk_platform_gb_channel_device_id unique (custom_device_id) +); + +create table IF NOT EXISTS wvp_platform_group +( + id serial primary key, + platform_id integer, + group_id integer, + constraint uk_wvp_platform_group_platform_id_group_id unique (platform_id, group_id) +); + +create table IF NOT EXISTS wvp_platform_region +( + id serial primary key, + platform_id integer, + region_id integer, + constraint uk_wvp_platform_region_platform_id_group_id unique (platform_id, region_id) +); + +create table IF NOT EXISTS wvp_record_plan +( + id serial primary key, + snap bool default false, + name varchar(255) NOT NULL, + create_time character varying(50), + update_time character varying(50) +); + +create table IF NOT EXISTS wvp_record_plan_item +( + id serial primary key, + start int, + stop int, + week_day int, + plan_id int, + create_time character varying(50), + update_time character varying(50) +); + + +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20250111`() +BEGIN + + DECLARE serverId VARCHAR(32) DEFAULT '你的服务ID'; + + IF EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_cloud_record' and INDEX_NAME = 'uk_stream_push_app_stream_path') + THEN + alter table wvp_cloud_record drop index uk_stream_push_app_stream_path ; + END IF; + + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_cloud_record' and column_name = 'folder') + THEN + alter table wvp_cloud_record modify folder varchar(500) null; + END IF; + + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_cloud_record' and column_name = 'file_path') + THEN + alter table wvp_cloud_record modify file_path varchar(500) null; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_cloud_record' and column_name = 'server_id') + THEN + alter table wvp_cloud_record add server_id character varying(50); + update wvp_cloud_record set server_id = serverId; + END IF; +END;// +call wvp_20250111(); +DROP PROCEDURE wvp_20250111; +DELIMITER ; + diff --git a/数据库/2.7.3/更新-mysql-2.7.3.sql b/数据库/2.7.3/更新-mysql-2.7.3.sql index 3cbc87297..6115ef1ac 100644 --- a/数据库/2.7.3/更新-mysql-2.7.3.sql +++ b/数据库/2.7.3/更新-mysql-2.7.3.sql @@ -1,64 +1,293 @@ +/* +* 20240528 +*/ +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20240528`() +BEGIN + IF NOT EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'transcode_suffix') + THEN + ALTER TABLE wvp_media_server ADD transcode_suffix character varying(255); + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'type') + THEN + alter table wvp_media_server + add type character varying(50) default 'zlm'; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'flv_port') + THEN + alter table wvp_media_server add flv_port integer; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'flv_ssl_port') + THEN + alter table wvp_media_server add flv_ssl_port integer; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'ws_flv_port') + THEN + alter table wvp_media_server add ws_flv_port integer; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'ws_flv_ssl_port') + THEN + alter table wvp_media_server add ws_flv_ssl_port integer; + END IF; +END; // +call wvp_20240528(); +DROP PROCEDURE wvp_20240528; +DELIMITER ; + +create table IF NOT EXISTS wvp_user_api_key ( + id serial primary key , + user_id bigint, + app character varying(255) , + api_key text, + expired_at bigint, + remark character varying(255), + enable bool default true, + create_time character varying(50), + update_time character varying(50) +); + /* * 20241222 */ -alter table wvp_device_channel - drop index uk_wvp_device_channel_unique_device_channel; -alter table wvp_device_channel - drop index uk_wvp_unique_stream_push_id; -alter table wvp_device_channel - drop index uk_wvp_unique_stream_proxy_id; +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20241222`() +BEGIN + IF EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and INDEX_NAME = 'uk_wvp_device_channel_unique_device_channel') + THEN + alter table wvp_device_channel drop index uk_wvp_device_channel_unique_device_channel; + END IF; -alter table wvp_device_channel - add data_type integer not null; + IF EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and INDEX_NAME = 'uk_wvp_unique_stream_push_id') + THEN + alter table wvp_device_channel drop index uk_wvp_unique_stream_push_id; + END IF; -alter table wvp_device_channel - add data_device_id integer not null; + IF EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and INDEX_NAME = 'uk_wvp_unique_stream_proxy_id') + THEN + alter table wvp_device_channel drop index uk_wvp_unique_stream_proxy_id; + END IF; -update wvp_device_channel wdc INNER JOIN - (SELECT id, device_db_id from wvp_device_channel where device_db_id is not null ) ct on ct.id = wdc.id -set wdc.data_type = 1, wdc.data_device_id = ct.device_db_id where wdc.device_db_id is not null; + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'data_type') + THEN + alter table wvp_device_channel add data_type integer not null; + END IF; -update wvp_device_channel wdc INNER JOIN - (SELECT id, stream_push_id from wvp_device_channel where stream_push_id is not null ) ct on ct.id = wdc.id -set wdc.data_type = 2, wdc.data_device_id = ct.stream_push_id where wdc.stream_push_id is not null; + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'data_device_id') + THEN + alter table wvp_device_channel add data_device_id integer not null; + END IF; -update wvp_device_channel wdc INNER JOIN - (SELECT id, stream_proxy_id from wvp_device_channel where stream_proxy_id is not null ) ct on ct.id = wdc.id -set wdc.data_type = 3, wdc.data_device_id = ct.stream_proxy_id where wdc.stream_proxy_id is not null; + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'device_db_id') + THEN + update wvp_device_channel wdc INNER JOIN + (SELECT id, device_db_id from wvp_device_channel where device_db_id is not null ) ct on ct.id = wdc.id + set wdc.data_type = 1, wdc.data_device_id = ct.device_db_id where wdc.device_db_id is not null; + alter table wvp_device_channel drop device_db_id; + END IF; -alter table wvp_device_channel drop device_db_id; -alter table wvp_device_channel drop stream_push_id; -alter table wvp_device_channel drop stream_proxy_id; + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'stream_push_id') + THEN + update wvp_device_channel wdc INNER JOIN + (SELECT id, stream_push_id from wvp_device_channel where stream_push_id is not null ) ct on ct.id = wdc.id + set wdc.data_type = 2, wdc.data_device_id = ct.stream_push_id where wdc.stream_push_id is not null; + alter table wvp_device_channel drop stream_push_id; + END IF; + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'stream_proxy_id') + THEN + update wvp_device_channel wdc INNER JOIN + (SELECT id, stream_proxy_id from wvp_device_channel where stream_proxy_id is not null ) ct on ct.id = wdc.id + set wdc.data_type = 3, wdc.data_device_id = ct.stream_proxy_id where wdc.stream_proxy_id is not null; + alter table wvp_device_channel drop stream_proxy_id; + END IF; +END; // +call wvp_20241222(); +DROP PROCEDURE wvp_20241222; +DELIMITER ; /* * 20241231 */ -alter table wvp_stream_proxy add relates_media_server_id character varying(50); - +DELIMITER // +CREATE PROCEDURE `wvp_20241231`() +BEGIN + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_stream_proxy' and column_name = 'relates_media_server_id') + THEN + alter table wvp_stream_proxy add relates_media_server_id character varying(50); + END IF; +END; // +call wvp_20241231(); +DROP PROCEDURE wvp_20241231; +DELIMITER ; /* * 20250111 */ -drop index uk_stream_push_app_stream_path on wvp_cloud_record; -alter table wvp_cloud_record change folder folder varchar(500) null; -alter table wvp_cloud_record change file_path file_path varchar(500) null; +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20250111`() +BEGIN + IF EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_cloud_record' and INDEX_NAME = 'uk_stream_push_app_stream_path') + THEN + alter table wvp_cloud_record drop index uk_stream_push_app_stream_path ; + END IF; + + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_cloud_record' and column_name = 'folder') + THEN + alter table wvp_cloud_record modify folder varchar(500) null; + END IF; + + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_cloud_record' and column_name = 'file_path') + THEN + alter table wvp_cloud_record modify file_path varchar(500) null; + END IF; +END; // +call wvp_20250111(); +DROP PROCEDURE wvp_20250111; +DELIMITER ; /* * 20250211 */ -alter table wvp_device change keepalive_interval_time heart_beat_interval integer; -alter table wvp_device add heart_beat_count integer; -alter table wvp_device add position_capability integer; +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20250211`() +BEGIN + IF EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device' and column_name = 'keepalive_interval_time') + THEN + alter table wvp_device change keepalive_interval_time heart_beat_interval integer after as_message_channel; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device' and column_name = 'heart_beat_count') + THEN + alter table wvp_device add heart_beat_count integer; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device' and column_name = 'position_capability') + THEN + alter table wvp_device add position_capability integer; + END IF; +END; // +call wvp_20250211(); +DROP PROCEDURE wvp_20250211; +DELIMITER ; /** * 20250312 */ -alter table wvp_device add server_id character varying(50); -alter table wvp_media_server add server_id character varying(50); -alter table wvp_stream_proxy add server_id character varying(50); -alter table wvp_cloud_record add server_id character varying(50); -alter table wvp_platform add server_id character varying(50); +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20250312`() +BEGIN + DECLARE serverId VARCHAR(32) DEFAULT '你的服务ID'; + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device' and column_name = 'server_id') + THEN + alter table wvp_device add server_id character varying(50); + update wvp_device set server_id = serverId; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_media_server' and column_name = 'server_id') + THEN + alter table wvp_media_server add server_id character varying(50); + update wvp_media_server set server_id = serverId; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_stream_proxy' and column_name = 'server_id') + THEN + alter table wvp_stream_proxy add server_id character varying(50); + update wvp_stream_proxy set server_id = serverId; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_cloud_record' and column_name = 'server_id') + THEN + alter table wvp_cloud_record add server_id character varying(50); + update wvp_cloud_record set server_id = serverId; + END IF; + + IF not EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_platform' and column_name = 'server_id') + THEN + alter table wvp_platform add server_id character varying(50); + END IF; +END; // +call wvp_20250312(); +DROP PROCEDURE wvp_20250312; +DELIMITER ; + +/* +* 20250319 +*/ +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20250319`() +BEGIN + IF NOT EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'gps_speed') + THEN + alter table wvp_device_channel add gps_speed double precision; + END IF; + + IF NOT EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'gps_altitude') + THEN + alter table wvp_device_channel add gps_altitude double precision; + END IF; + + IF NOT EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and column_name = 'gps_direction') + THEN + alter table wvp_device_channel add gps_direction double precision; + END IF; +END; // +call wvp_20250319(); +DROP PROCEDURE wvp_20250319; +DELIMITER ; + +/* +* 20250402 +*/ +DELIMITER // -- 重定义分隔符避免分号冲突 +CREATE PROCEDURE `wvp_20250402`() +BEGIN + IF NOT EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and INDEX_NAME = 'data_type') + THEN + create index data_type on wvp_device_channel (data_type); + END IF; + IF NOT EXISTS (SELECT column_name FROM information_schema.STATISTICS + WHERE TABLE_SCHEMA = (SELECT DATABASE()) and table_name = 'wvp_device_channel' and INDEX_NAME = 'data_device_id') + THEN + create index data_device_id on wvp_device_channel (data_device_id); + END IF; + +END; // +call wvp_20250402(); +DROP PROCEDURE wvp_20250402; +DELIMITER ; + + -update wvp_device set server_id = "你服务的ID"; -update wvp_media_server set server_id = "你服务的ID"; -update wvp_stream_proxy set server_id = "你服务的ID"; -update wvp_cloud_record set server_id = "你服务的ID"; diff --git a/数据库/2.7.3/更新-postgresql-kingbase-2.7.1升级到2.7.3.sql b/数据库/2.7.3/更新-postgresql-kingbase-2.7.1升级到2.7.3.sql new file mode 100644 index 000000000..289990058 --- /dev/null +++ b/数据库/2.7.3/更新-postgresql-kingbase-2.7.1升级到2.7.3.sql @@ -0,0 +1,390 @@ +drop table if exists wvp_resources_tree; +drop table if exists wvp_platform_catalog; +drop table if exists wvp_platform_gb_stream; +drop table if exists wvp_platform_gb_channel; +drop table if exists wvp_gb_stream; +drop table if exists wvp_log; +drop table IF EXISTS wvp_device; +drop table IF EXISTS wvp_platform; +drop table IF EXISTS wvp_media_server; +drop table IF EXISTS wvp_device_mobile_position; +drop table IF EXISTS wvp_device_channel; +drop table IF EXISTS wvp_stream_proxy; +drop table IF EXISTS wvp_stream_push; + +create table IF NOT EXISTS wvp_device +( + id serial primary key, + device_id character varying(50) not null, + name character varying(255), + manufacturer character varying(255), + model character varying(255), + firmware character varying(255), + transport character varying(50), + stream_mode character varying(50), + on_line bool default false, + register_time character varying(50), + keepalive_time character varying(50), + ip character varying(50), + create_time character varying(50), + update_time character varying(50), + port integer, + expires integer, + subscribe_cycle_for_catalog integer DEFAULT 0, + subscribe_cycle_for_mobile_position integer DEFAULT 0, + mobile_position_submission_interval integer DEFAULT 5, + subscribe_cycle_for_alarm integer DEFAULT 0, + host_address character varying(50), + charset character varying(50), + ssrc_check bool default false, + geo_coord_sys character varying(50), + media_server_id character varying(50) default 'auto', + custom_name character varying(255), + sdp_ip character varying(50), + local_ip character varying(50), + password character varying(255), + as_message_channel bool default false, + heart_beat_interval integer, + heart_beat_count integer, + position_capability integer, + broadcast_push_after_ack bool default false, + server_id character varying(50), + constraint uk_device_device unique (device_id) +); + +create table IF NOT EXISTS wvp_device_channel +( + id serial primary key, + device_id character varying(50), + name character varying(255), + manufacturer character varying(50), + model character varying(50), + owner character varying(50), + civil_code character varying(50), + block character varying(50), + address character varying(50), + parental integer, + parent_id character varying(50), + safety_way integer, + register_way integer, + cert_num character varying(50), + certifiable integer, + err_code integer, + end_time character varying(50), + secrecy integer, + ip_address character varying(50), + port integer, + password character varying(255), + status character varying(50), + longitude double precision, + latitude double precision, + ptz_type integer, + position_type integer, + room_type integer, + use_type integer, + supply_light_type integer, + direction_type integer, + resolution character varying(255), + business_group_id character varying(255), + download_speed character varying(255), + svc_space_support_mod integer, + svc_time_support_mode integer, + create_time character varying(50) not null, + update_time character varying(50) not null, + sub_count integer, + stream_id character varying(255), + has_audio bool default false, + gps_time character varying(50), + stream_identification character varying(50), + channel_type int default 0 not null, + gb_device_id character varying(50), + gb_name character varying(255), + gb_manufacturer character varying(255), + gb_model character varying(255), + gb_owner character varying(255), + gb_civil_code character varying(255), + gb_block character varying(255), + gb_address character varying(255), + gb_parental integer, + gb_parent_id character varying(255), + gb_safety_way integer, + gb_register_way integer, + gb_cert_num character varying(50), + gb_certifiable integer, + gb_err_code integer, + gb_end_time character varying(50), + gb_secrecy integer, + gb_ip_address character varying(50), + gb_port integer, + gb_password character varying(50), + gb_status character varying(50), + gb_longitude double precision, + gb_latitude double precision, + gb_business_group_id character varying(50), + gb_ptz_type integer, + gb_position_type integer, + gb_room_type integer, + gb_use_type integer, + gb_supply_light_type integer, + gb_direction_type integer, + gb_resolution character varying(255), + gb_download_speed character varying(255), + gb_svc_space_support_mod integer, + gb_svc_time_support_mode integer, + record_plan_id integer, + data_type integer not null, + data_device_id integer not null, + gps_speed double precision, + gps_altitude double precision, + gps_direction double precision, + constraint uk_wvp_unique_channel unique (gb_device_id) +); + +create index if not exists data_type on wvp_device_channel (data_type); +create index if not exists data_device_id on wvp_device_channel (data_device_id); + +create table IF NOT EXISTS wvp_device_mobile_position +( + id serial primary key, + device_id character varying(50) not null, + channel_id character varying(50) not null, + device_name character varying(255), + time character varying(50), + longitude double precision, + latitude double precision, + altitude double precision, + speed double precision, + direction double precision, + report_source character varying(50), + create_time character varying(50) +); + +create table IF NOT EXISTS wvp_media_server +( + id character varying(255) primary key, + ip character varying(50), + hook_ip character varying(50), + sdp_ip character varying(50), + stream_ip character varying(50), + http_port integer, + http_ssl_port integer, + rtmp_port integer, + rtmp_ssl_port integer, + rtp_proxy_port integer, + rtsp_port integer, + rtsp_ssl_port integer, + flv_port integer, + flv_ssl_port integer, + ws_flv_port integer, + ws_flv_ssl_port integer, + auto_config bool default false, + secret character varying(50), + type character varying(50) default 'zlm', + rtp_enable bool default false, + rtp_port_range character varying(50), + send_rtp_port_range character varying(50), + record_assist_port integer, + default_server bool default false, + create_time character varying(50), + update_time character varying(50), + hook_alive_interval integer, + record_path character varying(255), + record_day integer default 7, + transcode_suffix character varying(255), + server_id character varying(50), + constraint uk_media_server_unique_ip_http_port unique (ip, http_port, server_id) +); + +create table IF NOT EXISTS wvp_common_group +( + id serial primary key, + device_id varchar(50) NOT NULL, + name varchar(255) NOT NULL, + parent_id int, + parent_device_id varchar(50) DEFAULT NULL, + business_group varchar(50) NOT NULL, + create_time varchar(50) NOT NULL, + update_time varchar(50) NOT NULL, + civil_code varchar(50) default null, + constraint uk_common_group_device_platform unique (device_id) +); + +create table IF NOT EXISTS wvp_common_region +( + id serial primary key, + device_id varchar(50) NOT NULL, + name varchar(255) NOT NULL, + parent_id int, + parent_device_id varchar(50) DEFAULT NULL, + create_time varchar(50) NOT NULL, + update_time varchar(50) NOT NULL, + constraint uk_common_region_device_id unique (device_id) +); + +create table IF NOT EXISTS wvp_record_plan +( + id serial primary key, + snap bool default false, + name varchar(255) NOT NULL, + create_time character varying(50), + update_time character varying(50) +); + +create table IF NOT EXISTS wvp_record_plan_item +( + id serial primary key, + "start" int, + stop int, + week_day int, + plan_id int, + create_time character varying(50), + update_time character varying(50) +); + +create table IF NOT EXISTS wvp_platform +( + id serial primary key, + enable bool default false, + name character varying(255), + server_gb_id character varying(50), + server_gb_domain character varying(50), + server_ip character varying(50), + server_port integer, + device_gb_id character varying(50), + device_ip character varying(50), + device_port character varying(50), + username character varying(255), + password character varying(50), + expires character varying(50), + keep_timeout character varying(50), + transport character varying(50), + civil_code character varying(50), + manufacturer character varying(255), + model character varying(255), + address character varying(255), + character_set character varying(50), + ptz bool default false, + rtcp bool default false, + status bool default false, + catalog_group integer, + register_way integer, + secrecy integer, + create_time character varying(50), + update_time character varying(50), + as_message_channel bool default false, + catalog_with_platform integer default 1, + catalog_with_group integer default 1, + catalog_with_region integer default 1, + auto_push_channel bool default true, + send_stream_ip character varying(50), + server_id character varying(50), + constraint uk_platform_unique_server_gb_id unique (server_gb_id) +); + +create table IF NOT EXISTS wvp_platform_channel +( + id serial primary key, + platform_id integer, + device_channel_id integer, + custom_device_id character varying(50), + custom_name character varying(255), + custom_manufacturer character varying(50), + custom_model character varying(50), + custom_owner character varying(50), + custom_civil_code character varying(50), + custom_block character varying(50), + custom_address character varying(50), + custom_parental integer, + custom_parent_id character varying(50), + custom_safety_way integer, + custom_register_way integer, + custom_cert_num character varying(50), + custom_certifiable integer, + custom_err_code integer, + custom_end_time character varying(50), + custom_secrecy integer, + custom_ip_address character varying(50), + custom_port integer, + custom_password character varying(255), + custom_status character varying(50), + custom_longitude double precision, + custom_latitude double precision, + custom_ptz_type integer, + custom_position_type integer, + custom_room_type integer, + custom_use_type integer, + custom_supply_light_type integer, + custom_direction_type integer, + custom_resolution character varying(255), + custom_business_group_id character varying(255), + custom_download_speed character varying(255), + custom_svc_space_support_mod integer, + custom_svc_time_support_mode integer, + constraint uk_platform_gb_channel_platform_id_catalog_id_device_channel_id unique (platform_id, device_channel_id), + constraint uk_platform_gb_channel_device_id unique (custom_device_id) +); + +create table IF NOT EXISTS wvp_platform_group +( + id serial primary key, + platform_id integer, + group_id integer, + constraint uk_wvp_platform_group_platform_id_group_id unique (platform_id, group_id) +); + +create table IF NOT EXISTS wvp_platform_region +( + id serial primary key, + platform_id integer, + region_id integer, + constraint uk_wvp_platform_region_platform_id_group_id unique (platform_id, region_id) +); + +create table IF NOT EXISTS wvp_stream_proxy +( + id serial primary key, + type character varying(50), + app character varying(255), + stream character varying(255), + src_url character varying(255), + timeout integer, + ffmpeg_cmd_key character varying(255), + rtsp_type character varying(50), + media_server_id character varying(50), + enable_audio bool default false, + enable_mp4 bool default false, + pulling bool default false, + enable bool default false, + enable_remove_none_reader bool default false, + create_time character varying(50), + name character varying(255), + update_time character varying(50), + stream_key character varying(255), + server_id character varying(50), + enable_disable_none_reader bool default false, + relates_media_server_id character varying(50), + constraint uk_stream_proxy_app_stream unique (app, stream) +); + +create table IF NOT EXISTS wvp_stream_push +( + id serial primary key, + app character varying(255), + stream character varying(255), + create_time character varying(50), + media_server_id character varying(50), + server_id character varying(50), + push_time character varying(50), + status bool default false, + update_time character varying(50), + pushing bool default false, + self bool default false, + start_offline_push bool default true, + constraint uk_stream_push_app_stream unique (app, stream) +); +alter table wvp_cloud_record add column if not exists server_id character varying(50); +ALTER TABLE wvp_cloud_record DROP CONSTRAINT IF EXISTS uk_stream_push_app_stream_path; +alter table wvp_cloud_record alter folder type varchar(500); +alter table wvp_cloud_record alter file_path type varchar(500); +update wvp_cloud_record set server_id = '你的服务ID'; + diff --git a/数据库/2.7.3/更新-postgresql-kingbase-2.7.3.sql b/数据库/2.7.3/更新-postgresql-kingbase-2.7.3.sql index 8bc275a8d..334dc8dcf 100644 --- a/数据库/2.7.3/更新-postgresql-kingbase-2.7.3.sql +++ b/数据库/2.7.3/更新-postgresql-kingbase-2.7.3.sql @@ -1,63 +1,111 @@ +/* +* 20240528 +*/ +ALTER TABLE wvp_media_server ADD COLUMN IF NOT EXISTS transcode_suffix character varying(255); +ALTER table wvp_media_server ADD COLUMN IF NOT EXISTS type character varying(50) default 'zlm'; +ALTER table wvp_media_server ADD COLUMN IF NOT EXISTS flv_port integer; +ALTER table wvp_media_server ADD COLUMN IF NOT EXISTS flv_ssl_port integer; +ALTER table wvp_media_server ADD COLUMN IF NOT EXISTS ws_flv_port integer; +ALTER table wvp_media_server ADD COLUMN IF NOT EXISTS ws_flv_ssl_port integer; + + +create table IF NOT EXISTS wvp_user_api_key ( + id serial primary key , + user_id bigint, + app character varying(255) , + api_key text, + expired_at bigint, + remark character varying(255), + enable bool default true, + create_time character varying(50), + update_time character varying(50) +); + /* * 20241222 */ +ALTER TABLE wvp_device_channel drop CONSTRAINT IF EXISTS uk_wvp_device_channel_unique_device_channel; +ALTER TABLE wvp_device_channel DROP CONSTRAINT IF EXISTS uk_wvp_unique_stream_push_id; +ALTER TABLE wvp_device_channel DROP CONSTRAINT IF EXISTS uk_wvp_unique_stream_proxy_id; -alter table wvp_device_channel - drop index uk_wvp_device_channel_unique_device_channel; -alter table wvp_device_channel - drop index uk_wvp_unique_stream_push_id; -alter table wvp_device_channel - drop index uk_wvp_unique_stream_proxy_id; +ALTER TABLE wvp_device_channel ADD COLUMN IF NOT EXISTS data_type integer not null; +ALTER TABLE wvp_device_channel ADD COLUMN IF NOT EXISTS data_device_id integer not null; -alter table wvp_device_channel - add data_type integer not null; +DO $$ + BEGIN + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT current_schema()) and table_name = 'wvp_device_channel' and column_name = 'device_db_id') + THEN + update wvp_device_channel wdc set data_type = 1, data_device_id = + (SELECT device_db_id from wvp_device_channel where device_db_id is not null and id = wdc.id ) + where device_db_id is not null; + END IF; -alter table wvp_device_channel - add data_device_id integer not null; + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT current_schema()) and table_name = 'wvp_device_channel' and column_name = 'stream_push_id') + THEN + update wvp_device_channel wdc set data_type = 2, data_device_id = + (SELECT stream_push_id from wvp_device_channel where stream_push_id is not null and id = wdc.id ) + where stream_push_id is not null; + END IF; -update wvp_device_channel wdc -set data_type = 1, data_device_id = (SELECT device_db_id from wvp_device_channel where device_db_id is not null and id = wdc.id ) where device_db_id is not null; + IF EXISTS (SELECT column_name FROM information_schema.columns + WHERE TABLE_SCHEMA = (SELECT current_schema()) and table_name = 'wvp_device_channel' and column_name = 'stream_proxy_id') + THEN + update wvp_device_channel wdc set data_type = 3, data_device_id = (SELECT stream_proxy_id from wvp_device_channel where stream_proxy_id is not null and id = wdc.id ) + where stream_proxy_id is not null; + END IF; + END $$; -update wvp_device_channel wdc -set data_type = 2, data_device_id = (SELECT stream_push_id from wvp_device_channel where stream_push_id is not null and id = wdc.id ) where stream_push_id is not null; -update wvp_device_channel wdc -set data_type = 3, data_device_id = (SELECT stream_proxy_id from wvp_device_channel where stream_proxy_id is not null and id = wdc.id ) where stream_proxy_id is not null; - -alter table wvp_device_channel drop device_db_id; -alter table wvp_device_channel drop stream_push_id; -alter table wvp_device_channel drop stream_proxy_id; +alter table wvp_device_channel drop column IF EXISTS device_db_id; +alter table wvp_device_channel drop column IF EXISTS stream_push_id; +alter table wvp_device_channel drop column IF EXISTS stream_proxy_id; /* * 20241231 */ -alter table wvp_stream_proxy add relates_media_server_id character varying(50); - +alter table wvp_stream_proxy add column IF NOT EXISTS relates_media_server_id character varying(50); /* * 20250111 */ -drop index uk_stream_push_app_stream_path on wvp_cloud_record; -alter table wvp_cloud_record change folder folder varchar(500) null; -alter table wvp_cloud_record change file_path file_path varchar(500) null; +ALTER TABLE wvp_cloud_record DROP CONSTRAINT IF EXISTS uk_stream_push_app_stream_path; +alter table wvp_cloud_record alter folder type varchar(500); +alter table wvp_cloud_record alter file_path type varchar(500); /* * 20250211 */ -alter table wvp_device change keepalive_interval_time heart_beat_interval integer; -alter table wvp_device add heart_beat_count integer; -alter table wvp_device add position_capability integer; +alter table wvp_device rename keepalive_interval_time to heart_beat_interval; +alter table wvp_device add column if not exists heart_beat_count integer; +alter table wvp_device add column if not exists position_capability integer; /** * 20250312 */ -alter table wvp_device add server_id character varying(50); -alter table wvp_media_server add server_id character varying(50); -alter table wvp_stream_proxy add server_id character varying(50); -alter table wvp_cloud_record add server_id character varying(50); -alter table wvp_platform add server_id character varying(50); +alter table wvp_device add column if not exists server_id character varying(50); +alter table wvp_media_server add column if not exists server_id character varying(50); +alter table wvp_stream_proxy add column if not exists server_id character varying(50); +alter table wvp_cloud_record add column if not exists server_id character varying(50); +alter table wvp_platform add column if not exists server_id character varying(50); + +update wvp_device set server_id = '你的服务ID'; +update wvp_media_server set server_id = '你的服务ID'; +update wvp_stream_proxy set server_id = '你的服务ID'; +update wvp_cloud_record set server_id = '你的服务ID'; + +/* +* 20250319 +*/ +alter table wvp_device_channel add column if not exists gps_speed double precision; +alter table wvp_device_channel add column if not exists gps_altitude double precision; +alter table wvp_device_channel add column if not exists gps_direction double precision; + +/* +* 20250402 +*/ +create index if not exists data_type on wvp_device_channel (data_type); +create index if not exists data_device_id on wvp_device_channel (data_device_id); + -update wvp_device set server_id = "你服务的ID"; -update wvp_media_server set server_id = "你服务的ID"; -update wvp_stream_proxy set server_id = "你服务的ID"; -update wvp_cloud_record set server_id = "你服务的ID";