Commit 5a7a7a12bde268c104610d3e81a08df06ccab5eb
Merge branch 'wvp-28181-2.0' into main-dev
# Conflicts: # src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java # src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java # src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java # src/main/java/com/genersoft/iot/vmp/service/IPlayService.java # src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java # src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java # src/main/resources/all-application.yml # web_src/config/index.js # web_src/src/components/dialog/devicePlayer.vue
Showing
162 changed files
with
7373 additions
and
2905 deletions
README.md
| ... | ... | @@ -27,7 +27,7 @@ wvp使用文档 [https://doc.wvp-pro.cn](https://doc.wvp-pro.cn) |
| 27 | 27 | ZLM使用文档 [https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit) |
| 28 | 28 | > wvp文档由gitee提供服务,如果遇到打不开请多刷新几次。 |
| 29 | 29 | |
| 30 | -# 社群地址 | |
| 30 | +# 付费社群 | |
| 31 | 31 | [](https://t.zsxq.com/0d8VAD3Dm) |
| 32 | 32 | > 收费是为了提供更好的服务,也是对作者更大的激励。加入星球的用户三天后可以私信我留下微信号,我会拉大家入群。加入三天内不满意可以直接退款,大家不需要有顾虑,来白嫖三天也不是不可以。 |
| 33 | 33 | |
| ... | ... | @@ -104,6 +104,8 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git |
| 104 | 104 | - [X] 云端录像,推流/代理/国标视频均可以录制在云端服务器,支持预览和下载 |
| 105 | 105 | - [X] 支持打包可执行jar和war |
| 106 | 106 | - [X] 支持跨域请求,支持前后端分离部署 |
| 107 | +- [X] 支持Mysql,Postgresql,金仓等数据库 | |
| 108 | +- [X] 支持Onvif(目前在onvif分支,需要安装onvif服务,服务请在知识星球获取) | |
| 107 | 109 | |
| 108 | 110 | # 授权协议 |
| 109 | 111 | 本项目自有代码使用宽松的MIT协议,在保留版权信息的情况下可以自由应用于各自商用、非商业的项目。 但是本项目也零碎的使用了一些其他的开源代码,在商用的情况下请自行替代或剔除; 由于使用本项目而产生的商业纠纷或侵权行为一概与本项目及开发者无关,请自行承担法律风险。 在使用本项目代码时,也应该在授权协议中同时表明本项目依赖的第三方库的协议 | ... | ... |
doc/README.md
| ... | ... | @@ -14,7 +14,7 @@ |
| 14 | 14 | - 完全开源,且使用MIT许可协议。保留版权的情况下可以用于商业项目。 |
| 15 | 15 | - 支持多流媒体节点负载均衡。 |
| 16 | 16 | |
| 17 | -# 社群 | |
| 17 | +# 付费社群 | |
| 18 | 18 | [](https://t.zsxq.com/0d8VAD3Dm) |
| 19 | 19 | > 收费是为了提供更好的服务,也是对作者更大的激励。加入星球的用户三天后可以私信我留下微信号,我会拉大家入群。加入三天内不满意可以直接退款,大家不需要有顾虑,来白嫖三天也不是不可以。 |
| 20 | 20 | |
| ... | ... | @@ -62,16 +62,16 @@ |
| 62 | 62 | - [X] 注册 |
| 63 | 63 | - [X] 注销 |
| 64 | 64 | - [X] 实时视音频点播 |
| 65 | -- [ ] 设备控制 | |
| 66 | - - [ ] 云台控制 | |
| 65 | +- [X] 设备控制 | |
| 66 | + - [X] 云台控制 | |
| 67 | 67 | - [ ] 远程启动 |
| 68 | - - [ ] 录像控制 | |
| 69 | - - [ ] 报警布防/撤防 | |
| 70 | - - [ ] 报警复位 | |
| 71 | - - [ ] 强制关键帧 | |
| 72 | - - [ ] 拉框放大 | |
| 73 | - - [ ] 拉框缩小 | |
| 74 | - - [ ] 看守位控制 | |
| 68 | + - [X] 录像控制 | |
| 69 | + - [X] 报警布防/撤防 | |
| 70 | + - [X] 报警复位 | |
| 71 | + - [X] 强制关键帧 | |
| 72 | + - [X] 拉框放大 | |
| 73 | + - [X] 拉框缩小 | |
| 74 | + - [X] 看守位控制 | |
| 75 | 75 | - [ ] 设备配置 |
| 76 | 76 | - [ ] 报警事件通知和分发 |
| 77 | 77 | - [X] 设备目录订阅 |
| ... | ... | @@ -79,7 +79,7 @@ |
| 79 | 79 | - [X] 设备目录查询 |
| 80 | 80 | - [X] 设备状态查询 |
| 81 | 81 | - [ ] 设备配置查询 |
| 82 | - - [ ] 设备预置位查询 | |
| 82 | + - [X] 设备预置位查询 | |
| 83 | 83 | - [X] 状态信息报送 |
| 84 | 84 | - [X] 设备视音频文件检索 |
| 85 | 85 | - [X] 历史视音频的回放 |
| ... | ... | @@ -87,7 +87,7 @@ |
| 87 | 87 | - [x] 暂停 |
| 88 | 88 | - [x] 进/退 |
| 89 | 89 | - [x] 停止 |
| 90 | -- [ ] 视音频文件下载 | |
| 90 | +- [X] 视音频文件下载 | |
| 91 | 91 | - [ ] ~~校时~~ |
| 92 | 92 | - [X] 订阅和通知 |
| 93 | 93 | - [X] 事件订阅 | ... | ... |
doc/_content/introduction/config.md
| ... | ... | @@ -29,10 +29,53 @@ java -jar wvp-pro-*.jar |
| 29 | 29 | ``` |
| 30 | 30 | 这也是我自己最常用的方式。 |
| 31 | 31 | ## 2 配置WVP-PRO |
| 32 | -### 2.1 Mysql数据库配置 | |
| 33 | -首先你需要创建一个名为wvp(也可使用其他名字)的数据库,并使用sql/mysql.sql导入数据库,初始化数据库结构。 | |
| 34 | -(这里注意,取决于版本,新版的sql文件夹下有update.sql,补丁包,一定要注意运行导入) | |
| 35 | -在application-dev.yml中配置(使用1.2方式的是在jar包的同级目录的application.yml)配置数据库连接,包括数据库连接信息,密码。 | |
| 32 | +wvp支持多种数据库,包括Mysql,Postgresql,金仓等,配置任选一种即可。 | |
| 33 | +### 2.1 数据库配置 | |
| 34 | +#### 2.1.1 初始化数据库 | |
| 35 | +首先使用创建数据库,然后使用sql/初始化.sql初始化数据库,如果是从旧版升级上来的,使用升级sql更新。 | |
| 36 | +#### 2.1.2 Mysql数据库配置 | |
| 37 | +数据库名称以wvp为例 | |
| 38 | +```yaml | |
| 39 | +spring: | |
| 40 | + datasource: | |
| 41 | + type: com.zaxxer.hikari.HikariDataSource | |
| 42 | + driver-class-name: com.mysql.cj.jdbc.Driver | |
| 43 | + url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true | |
| 44 | + username: root | |
| 45 | + password: 12345678 | |
| 46 | + | |
| 47 | +mybatis: | |
| 48 | + configuration: | |
| 49 | + map-underscore-to-camel-case: true | |
| 50 | +``` | |
| 51 | +#### 2.1.3 Postgresql数据库配置 | |
| 52 | +数据库名称以wvp为例 | |
| 53 | +```yaml | |
| 54 | +spring: | |
| 55 | + datasource: | |
| 56 | + type: com.zaxxer.hikari.HikariDataSource | |
| 57 | + driver-class-name: org.postgresql.Driver | |
| 58 | + url: jdbc:postgresql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true | |
| 59 | + username: root | |
| 60 | + password: 12345678 | |
| 61 | + | |
| 62 | +pagehelper: | |
| 63 | + helper-dialect: postgresql | |
| 64 | +``` | |
| 65 | +#### 2.1.4 金仓数据库配置 | |
| 66 | +数据库名称以wvp为例 | |
| 67 | +```yaml | |
| 68 | +spring: | |
| 69 | + datasource: | |
| 70 | + type: com.zaxxer.hikari.HikariDataSource | |
| 71 | + driver-class-name: com.kingbase8.Driver | |
| 72 | + url: jdbc:kingbase8://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=utf8 | |
| 73 | + username: root | |
| 74 | + password: 12345678 | |
| 75 | + | |
| 76 | +pagehelper: | |
| 77 | + helper-dialect: postgresql | |
| 78 | +``` | |
| 36 | 79 | ### 2.2 Redis数据库配置 |
| 37 | 80 | 配置wvp中的redis连接信息,建议wvp自己单独使用一个db。 |
| 38 | 81 | ### 2.3 配置服务启动端口(可直接使用默认配置) | ... | ... |
doc/_media/1372762149.jpg
0 → 100644
126 KB
doc/_media/903207146.jpg
0 → 100644
131 KB
doc/_media/logo.jpg
0 → 100644
102 KB
doc/index.html
| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | <meta name="description" content="Description"> |
| 8 | 8 | <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0"> |
| 9 | 9 | <link rel="icon" href="_media/favicon.ico" type="image/x-icon" /> |
| 10 | - <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css"> | |
| 10 | + <link rel="stylesheet" href="./lib/css/vue.css"> | |
| 11 | 11 | <!-- <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/lib/themes/dark.css">--> |
| 12 | 12 | <style> |
| 13 | 13 | .cover{ |
| ... | ... | @@ -47,11 +47,11 @@ |
| 47 | 47 | } |
| 48 | 48 | </script> |
| 49 | 49 | <!-- Docsify v4 --> |
| 50 | - <script src="//cdn.jsdelivr.net/npm/docsify@4"></script> | |
| 51 | - <script src="//unpkg.com/docsify-plantuml/dist/docsify-plantuml.min.js"></script> | |
| 52 | - <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script> | |
| 53 | - <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/zoom-image.min.js"></script> | |
| 54 | - <script src="//cdn.jsdelivr.net/npm/docsify-copy-code/dist/docsify-copy-code.min.js"></script> | |
| 50 | + <script src="./lib/js/docsify@4.js"></script> | |
| 51 | + <script src="./lib/js/docsify-plantuml.min.js"></script> | |
| 52 | + <script src="./lib/js/search.min.js"></script> | |
| 53 | + <script src="./lib/js/zoom-image.min.js"></script> | |
| 54 | + <script src="./lib/js/docsify-copy-code.min.js"></script> | |
| 55 | 55 | |
| 56 | 56 | </script> |
| 57 | 57 | <!-- <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/disqus.min.js"></script>--> | ... | ... |
doc/lib/css/vue.css
0 → 100644
| 1 | +@import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600");*{-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:none;-webkit-touch-callout:none;box-sizing:border-box}body:not(.ready){overflow:hidden}body:not(.ready) .app-nav,body:not(.ready)>nav,body:not(.ready) [data-cloak]{display:none}div#app{font-size:30px;font-weight:lighter;margin:40vh auto;text-align:center}div#app:empty:before{content:"Loading..."}img.emoji{height:1.2em}img.emoji,span.emoji{vertical-align:middle}span.emoji{font-family:Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-size:1.2em}.progress{background-color:#42b983;background-color:var(--theme-color,#42b983);height:2px;left:0;position:fixed;right:0;top:0;transition:width .2s,opacity .4s;width:0;z-index:999999}.search .search-keyword,.search a:hover{color:#42b983;color:var(--theme-color,#42b983)}.search .search-keyword{font-style:normal;font-weight:700}body,html{height:100%}body{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;color:#34495e;font-family:Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:15px;letter-spacing:0;margin:0;overflow-x:hidden}img{max-width:100%}a[disabled]{cursor:not-allowed;opacity:.6}kbd{border:1px solid #ccc;border-radius:3px;display:inline-block;font-size:12px!important;line-height:12px;margin-bottom:3px;padding:3px 5px;vertical-align:middle}li input[type=checkbox]{margin:0 .2em .25em 0;vertical-align:middle}.app-nav{margin:25px 60px 0 0;position:absolute;right:0;text-align:right;z-index:10}.app-nav.no-badge{margin-right:25px}.app-nav p{margin:0}.app-nav>a{margin:0 1rem;padding:5px 0}.app-nav li,.app-nav ul{display:inline-block;list-style:none;margin:0}.app-nav a{color:inherit;font-size:16px;text-decoration:none;transition:color .3s}.app-nav a.active,.app-nav a:hover{color:#42b983;color:var(--theme-color,#42b983)}.app-nav a.active{border-bottom:2px solid #42b983;border-bottom:2px solid var(--theme-color,#42b983)}.app-nav li{display:inline-block;margin:0 1rem;padding:5px 0;position:relative;cursor:pointer}.app-nav li ul{background-color:#fff;border:1px solid;border-color:#ddd #ddd #ccc;border-radius:4px;box-sizing:border-box;display:none;max-height:calc(100vh - 61px);overflow-y:auto;padding:10px 0;position:absolute;right:-15px;text-align:left;top:100%;white-space:nowrap}.app-nav li ul li{display:block;font-size:14px;line-height:1rem;margin:8px 14px;white-space:nowrap}.app-nav li ul a{display:block;font-size:inherit;margin:0;padding:0}.app-nav li ul a.active{border-bottom:0}.app-nav li:hover ul{display:block}.github-corner{border-bottom:0;position:fixed;right:0;text-decoration:none;top:0;z-index:1}.github-corner:hover .octo-arm{animation:octocat-wave .56s ease-in-out}.github-corner svg{color:#fff;fill:#42b983;fill:var(--theme-color,#42b983);height:80px;width:80px}main{display:block;position:relative;width:100vw;height:100%;z-index:0}main.hidden{display:none}.anchor{display:inline-block;text-decoration:none;transition:all .3s}.anchor span{color:#34495e}.anchor:hover{text-decoration:underline}.sidebar{border-right:1px solid rgba(0,0,0,.07);overflow-y:auto;padding:40px 0 0;position:absolute;top:0;bottom:0;left:0;transition:transform .25s ease-out;width:300px;z-index:20}.sidebar>h1{margin:0 auto 1rem;font-size:1.5rem;font-weight:300;text-align:center}.sidebar>h1 a{color:inherit;text-decoration:none}.sidebar>h1 .app-nav{display:block;position:static}.sidebar .sidebar-nav{line-height:2em;padding-bottom:40px}.sidebar li.collapse .app-sub-sidebar{display:none}.sidebar ul{margin:0 0 0 15px;padding:0}.sidebar li>p{font-weight:700;margin:0}.sidebar ul,.sidebar ul li{list-style:none}.sidebar ul li a{border-bottom:none;display:block}.sidebar ul li ul{padding-left:20px}.sidebar::-webkit-scrollbar{width:4px}.sidebar::-webkit-scrollbar-thumb{background:transparent;border-radius:4px}.sidebar:hover::-webkit-scrollbar-thumb{background:hsla(0,0%,53.3%,.4)}.sidebar:hover::-webkit-scrollbar-track{background:hsla(0,0%,53.3%,.1)}.sidebar-toggle{background-color:transparent;background-color:hsla(0,0%,100%,.8);border:0;outline:none;padding:10px;position:absolute;bottom:0;left:0;text-align:center;transition:opacity .3s;width:284px;z-index:30;cursor:pointer}.sidebar-toggle:hover .sidebar-toggle-button{opacity:.4}.sidebar-toggle span{background-color:#42b983;background-color:var(--theme-color,#42b983);display:block;margin-bottom:4px;width:16px;height:2px}body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}.content{padding-top:60px;position:absolute;top:0;right:0;bottom:0;left:300px;transition:left .25s ease}.markdown-section{margin:0 auto;max-width:80%;padding:30px 15px 40px;position:relative}.markdown-section>*{box-sizing:border-box;font-size:inherit}.markdown-section>:first-child{margin-top:0!important}.markdown-section hr{border:none;border-bottom:1px solid #eee;margin:2em 0}.markdown-section iframe{border:1px solid #eee;width:1px;min-width:100%}.markdown-section table{border-collapse:collapse;border-spacing:0;display:block;margin-bottom:1rem;overflow:auto;width:100%}.markdown-section th{font-weight:700}.markdown-section td,.markdown-section th{border:1px solid #ddd;padding:6px 13px}.markdown-section tr{border-top:1px solid #ccc}.markdown-section p.tip,.markdown-section tr:nth-child(2n){background-color:#f8f8f8}.markdown-section p.tip{border-bottom-right-radius:2px;border-left:4px solid #f66;border-top-right-radius:2px;margin:2em 0;padding:12px 24px 12px 30px;position:relative}.markdown-section p.tip:before{background-color:#f66;border-radius:100%;color:#fff;content:"!";font-family:Dosis,Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:14px;font-weight:700;left:-12px;line-height:20px;position:absolute;height:20px;width:20px;text-align:center;top:14px}.markdown-section p.tip code{background-color:#efefef}.markdown-section p.tip em{color:#34495e}.markdown-section p.warn{background:rgba(66,185,131,.1);border-radius:2px;padding:1rem}.markdown-section ul.task-list>li{list-style-type:none}body.close .sidebar{transform:translateX(-300px)}body.close .sidebar-toggle{width:auto}body.close .content{left:0}@media print{.app-nav,.github-corner,.sidebar,.sidebar-toggle{display:none}}@media screen and (max-width:768px){.github-corner,.sidebar,.sidebar-toggle{position:fixed}.app-nav{margin-top:16px}.app-nav li ul{top:30px}main{height:auto;min-height:100vh;overflow-x:hidden}.sidebar{left:-300px;transition:transform .25s ease-out}.content{left:0;max-width:100vw;position:static;padding-top:20px;transition:transform .25s ease}.app-nav,.github-corner{transition:transform .25s ease-out}.sidebar-toggle{background-color:transparent;width:auto;padding:30px 30px 10px 10px}body.close .sidebar{transform:translateX(300px)}body.close .sidebar-toggle{background-color:hsla(0,0%,100%,.8);transition:background-color 1s;width:284px;padding:10px}body.close .content{transform:translateX(300px)}body.close .app-nav,body.close .github-corner{display:none}.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave .56s ease-in-out}}@keyframes octocat-wave{0%,to{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}section.cover{position:relative;align-items:center;background-position:50%;background-repeat:no-repeat;background-size:cover;min-height:100vh;width:100%;display:none}section.cover.show{display:flex}section.cover.has-mask .mask{background-color:#fff;opacity:.8;position:absolute;top:0;bottom:0;width:100%}section.cover .cover-main{flex:1;margin:0 16px;text-align:center;position:relative}section.cover a{color:inherit}section.cover a,section.cover a:hover{text-decoration:none}section.cover p{line-height:1.5rem;margin:1em 0}section.cover h1{color:inherit;font-size:2.5rem;font-weight:300;margin:.625rem 0 2.5rem;position:relative;text-align:center}section.cover h1 a{display:block}section.cover h1 small{bottom:-.4375rem;font-size:1rem;position:absolute}section.cover blockquote{font-size:1.5rem;text-align:center}section.cover ul{line-height:1.8;list-style-type:none;margin:1em auto;max-width:500px;padding:0}section.cover .cover-main>p:last-child a{border-radius:2rem;border:1px solid #42b983;border-color:var(--theme-color,#42b983);box-sizing:border-box;color:#42b983;color:var(--theme-color,#42b983);display:inline-block;font-size:1.05rem;letter-spacing:.1rem;margin:.5rem 1rem;padding:.75em 2rem;text-decoration:none;transition:all .15s ease}section.cover .cover-main>p:last-child a:last-child{background-color:#42b983;background-color:var(--theme-color,#42b983);color:#fff}section.cover .cover-main>p:last-child a:last-child:hover{color:inherit;opacity:.8}section.cover .cover-main>p:last-child a:hover{color:inherit}section.cover blockquote>p>a{border-bottom:2px solid #42b983;border-bottom:2px solid var(--theme-color,#42b983);transition:color .3s}section.cover blockquote>p>a:hover{color:#42b983;color:var(--theme-color,#42b983)}.sidebar,body{background-color:#fff}.sidebar{color:#364149}.sidebar li{margin:6px 0}.sidebar ul li a{color:#505d6b;font-size:14px;font-weight:400;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.sidebar ul li a:hover{text-decoration:underline}.sidebar ul li ul{padding:0}.sidebar ul li.active>a{border-right:2px solid;color:#42b983;color:var(--theme-color,#42b983);font-weight:600}.app-sub-sidebar li:before{content:"-";padding-right:4px;float:left}.markdown-section h1,.markdown-section h2,.markdown-section h3,.markdown-section h4,.markdown-section strong{color:#2c3e50;font-weight:600}.markdown-section a{color:#42b983;color:var(--theme-color,#42b983);font-weight:600}.markdown-section h1{font-size:2rem;margin:0 0 1rem}.markdown-section h2{font-size:1.75rem;margin:45px 0 .8rem}.markdown-section h3{font-size:1.5rem;margin:40px 0 .6rem}.markdown-section h4{font-size:1.25rem}.markdown-section h5{font-size:1rem}.markdown-section h6{color:#777;font-size:1rem}.markdown-section figure,.markdown-section p{margin:1.2em 0}.markdown-section ol,.markdown-section p,.markdown-section ul{line-height:1.6rem;word-spacing:.05rem}.markdown-section ol,.markdown-section ul{padding-left:1.5rem}.markdown-section blockquote{border-left:4px solid #42b983;border-left:4px solid var(--theme-color,#42b983);color:#858585;margin:2em 0;padding-left:20px}.markdown-section blockquote p{font-weight:600;margin-left:0}.markdown-section iframe{margin:1em 0}.markdown-section em{color:#7f8c8d}.markdown-section code,.markdown-section output:after,.markdown-section pre{font-family:Roboto Mono,Monaco,courier,monospace}.markdown-section code,.markdown-section pre{background-color:#f8f8f8}.markdown-section output,.markdown-section pre{margin:1.2em 0;position:relative}.markdown-section output,.markdown-section pre>code{border-radius:2px;display:block}.markdown-section output:after,.markdown-section pre>code{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial}.markdown-section code{border-radius:2px;color:#e96900;margin:0 2px;padding:3px 5px;white-space:pre-wrap}.markdown-section>:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) code{font-size:.8rem}.markdown-section pre{padding:0 1.4rem;line-height:1.5rem;overflow:auto;word-wrap:normal}.markdown-section pre>code{color:#525252;font-size:.8rem;padding:2.2em 5px;line-height:inherit;margin:0 2px;max-width:inherit;overflow:inherit;white-space:inherit}.markdown-section output{padding:1.7rem 1.4rem;border:1px dotted #ccc}.markdown-section output>:first-child{margin-top:0}.markdown-section output>:last-child{margin-bottom:0}.markdown-section code:after,.markdown-section code:before,.markdown-section output:after,.markdown-section output:before{letter-spacing:.05rem}.markdown-section output:after,.markdown-section pre:after{color:#ccc;font-size:.6rem;font-weight:600;height:15px;line-height:15px;padding:5px 10px 0;position:absolute;right:0;text-align:right;top:0;content:attr(data-lang)}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8e908c}.token.namespace{opacity:.7}.token.boolean,.token.number{color:#c76b29}.token.punctuation{color:#525252}.token.property{color:#c08b30}.token.tag{color:#2973b7}.token.string{color:#42b983;color:var(--theme-color,#42b983)}.token.selector{color:#6679cc}.token.attr-name{color:#2973b7}.language-css .token.string,.style .token.string,.token.entity,.token.url{color:#22a2c9}.token.attr-value,.token.control,.token.directive,.token.unit{color:#42b983;color:var(--theme-color,#42b983)}.token.function,.token.keyword{color:#e96900}.token.atrule,.token.regex,.token.statement{color:#22a2c9}.token.placeholder,.token.variable{color:#3d8fd1}.token.deleted{text-decoration:line-through}.token.inserted{border-bottom:1px dotted #202746;text-decoration:none}.token.italic{font-style:italic}.token.bold,.token.important{font-weight:700}.token.important{color:#c94922}.token.entity{cursor:help}code .token{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;min-height:1.5rem;position:relative;left:auto} | |
| 0 | 2 | \ No newline at end of file | ... | ... |
doc/lib/js/docsify-copy-code.min.js
0 → 100644
| 1 | +/*! | |
| 2 | + * docsify-copy-code | |
| 3 | + * v2.1.1 | |
| 4 | + * https://github.com/jperasmus/docsify-copy-code | |
| 5 | + * (c) 2017-2020 JP Erasmus <jperasmus11@gmail.com> | |
| 6 | + * MIT license | |
| 7 | + */ | |
| 8 | +!function(){"use strict";function s(o){return(s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(o){return typeof o}:function(o){return o&&"function"==typeof Symbol&&o.constructor===Symbol&&o!==Symbol.prototype?"symbol":typeof o})(o)}!function(o,e){void 0===e&&(e={});var t=e.insertAt;if(o&&"undefined"!=typeof document){var n=document.head||document.getElementsByTagName("head")[0],c=document.createElement("style");c.type="text/css","top"===t&&n.firstChild?n.insertBefore(c,n.firstChild):n.appendChild(c),c.styleSheet?c.styleSheet.cssText=o:c.appendChild(document.createTextNode(o))}}(".docsify-copy-code-button,.docsify-copy-code-button span{cursor:pointer;transition:all .25s ease}.docsify-copy-code-button{position:absolute;z-index:1;top:0;right:0;overflow:visible;padding:.65em .8em;border:0;border-radius:0;outline:0;font-size:1em;background:grey;background:var(--theme-color,grey);color:#fff;opacity:0}.docsify-copy-code-button span{border-radius:3px;background:inherit;pointer-events:none}.docsify-copy-code-button .error,.docsify-copy-code-button .success{position:absolute;z-index:-100;top:50%;right:0;padding:.5em .65em;font-size:.825em;opacity:0;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.docsify-copy-code-button.error .error,.docsify-copy-code-button.success .success{right:100%;opacity:1;-webkit-transform:translate(-115%,-50%);transform:translate(-115%,-50%)}.docsify-copy-code-button:focus,pre:hover .docsify-copy-code-button{opacity:1}"),document.querySelector('link[href*="docsify-copy-code"]')&&console.warn("[Deprecation] Link to external docsify-copy-code stylesheet is no longer necessary."),window.DocsifyCopyCodePlugin={init:function(){return function(o,e){o.ready(function(){console.warn("[Deprecation] Manually initializing docsify-copy-code using window.DocsifyCopyCodePlugin.init() is no longer necessary.")})}}},window.$docsify=window.$docsify||{},window.$docsify.plugins=[function(o,r){o.doneEach(function(){var o=Array.apply(null,document.querySelectorAll("pre[data-lang]")),c={buttonText:"Copy to clipboard",errorText:"Error",successText:"Copied"};r.config.copyCode&&Object.keys(c).forEach(function(t){var n=r.config.copyCode[t];"string"==typeof n?c[t]=n:"object"===s(n)&&Object.keys(n).some(function(o){var e=-1<location.href.indexOf(o);return c[t]=e?n[o]:c[t],e})});var e=['<button class="docsify-copy-code-button">','<span class="label">'.concat(c.buttonText,"</span>"),'<span class="error">'.concat(c.errorText,"</span>"),'<span class="success">'.concat(c.successText,"</span>"),"</button>"].join("");o.forEach(function(o){o.insertAdjacentHTML("beforeend",e)})}),o.mounted(function(){document.querySelector(".content").addEventListener("click",function(o){if(o.target.classList.contains("docsify-copy-code-button")){var e="BUTTON"===o.target.tagName?o.target:o.target.parentNode,t=document.createRange(),n=e.parentNode.querySelector("code"),c=window.getSelection();t.selectNode(n),c.removeAllRanges(),c.addRange(t);try{document.execCommand("copy")&&(e.classList.add("success"),setTimeout(function(){e.classList.remove("success")},1e3))}catch(o){console.error("docsify-copy-code: ".concat(o)),e.classList.add("error"),setTimeout(function(){e.classList.remove("error")},1e3)}"function"==typeof(c=window.getSelection()).removeRange?c.removeRange(t):"function"==typeof c.removeAllRanges&&c.removeAllRanges()}})})}].concat(window.$docsify.plugins||[])}(); | |
| 9 | +//# sourceMappingURL=docsify-copy-code.min.js.map | ... | ... |
doc/lib/js/docsify-plantuml.min.js
0 → 100644
| 1 | +!function(t){function e(a){if(n[a])return n[a].exports;var r=n[a]={i:a,l:!1,exports:{}};return t[a].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var n={};e.m=t,e.c=n,e.d=function(t,n,a){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:a})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=0)}([function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var a=n(1);window.$docsify||(window.$docsify={}),window.$docsify.plugins=(window.$docsify.plugins||[]).concat(a.a)},function(t,e,n){"use strict";function a(t,e){var t=Object(o.a)(e.skin)+t,n=e.serverPath||"//www.plantuml.com/plantuml/svg/";if(e.renderSvgAsObject){var a=n+Object(l.encode)(r(t));return'<object type="image/svg+xml" data="'+a+'" />'}var a=n+Object(l.encode)(t);return'<img src="'+a+'" />'}function r(t){function e(t,e){for(var n=(a+e).split("/"),r=[],i=0,s=n.length;i<s;i++){var o=n[i];".."===o?r.pop():"."!==o&&r.push(o)}return"[["+r.join("/")}var n=window.location.toString(),a=n.substring(0,n.lastIndexOf("/")+1);return t.replace(/\[\[\$((?:\.?\.\/)*)/g,e)}function i(t,e,n){var r=window.Docsify.dom,i=r.create("span",t);return i.querySelectorAll?((r.findAll(i,e)||[]).forEach(function(t){var e=t.parentNode,i=r.create("p",a(t.innerText,n));e&&(i.dataset.lang=h,t.parentNode.replaceChild(i,t))}),i.innerHTML):t}function s(t,e){const n=Object.assign({},{skin:"default",renderSvgAsObject:!1},e.config.plantuml);t.afterEach(function(t){return i(t,d,n)})}e.a=s;var o=n(2),l=n(5),h=(n.n(l),"plantuml"),d='pre[data-lang="'+h+'"]'},function(t,e,n){"use strict";function a(t){return t in l?l[t]:(console.warn("[Docsify-PlantUML] Invalid skin name: "+t),l[h])}e.a=a;var r=n(3),i=n.n(r),s=n(4),o=n.n(s);const l={default:i.a,classic:o.a},h="default"},function(t,e){t.exports="' fork from https://github.com/matthewjosephtaylor/plantuml-style/blob/master/style.pu\n' Not-ugly plantuml style defaults\n\nskinparam defaultFontName Helvetica\nskinparam defaultFontSize 12\nskinparam sequenceMessageAlign center\nskinparam monochrome true\nskinparam shadowing false\n\nskinparam activity {\n\tArrowColor Black\n\tBackgroundColor White\n\tBorderColor Black\n\tBorderThickness 1\n}\n\nskinparam actor {\n\tBackgroundColor White\n\tBorderColor Black\n}\n\nskinparam usecase {\n\tArrowColor Black\n\tBackgroundColor White\n\tBorderColor Black\n\tBorderThickness 1\n}\n\nskinparam class {\n\tArrowColor Black\n\tBackgroundColor White\n\tBorderColor Black\n\tBorderThickness 1\n}\n\n\nskinparam object {\n\tArrowColor Black\n\tBackgroundColor White\n\tBorderColor Black\n}\n\nskinparam package {\n\tBackgroundColor White\n\tBorderColor Black\n}\n\n'TODO stereotype\n\nskinparam component {\n\tBackgroundColor White\n\tInterfaceBackgroundColor White\n\tBorderColor Black\n\tInterfaceBorderColor Black\n}\n\nskinparam note {\n\tBackgroundColor White\n\tBorderColor Black\n}\n\nskinparam state {\n\tArrowColor Black\n\tBackgroundColor White\n\tBorderColor Black\n}\n\nskinparam sequence {\n\tArrowColor Black\n\tBackgroundColor White\n\tParticipantBackgroundColor White\n\tBorderColor Black\n\tLifeLineBorderColor Black\n\tParticipantBorderColor Black\n\tBoxLineColor Black\n}\n\nskinparam interface {\n\tBackgroundColor White\n\tBorderColor Black\n}\n"},function(t,e){t.exports=""},function(t,e,n){t.exports={encode:n(6).encode,decode:n(7).decode}},function(t,e,n){var a,a;!function(e){t.exports=e()}(function(){return function(){function t(e,n,r){function i(o,l){if(!n[o]){if(!e[o]){var h="function"==typeof a&&a;if(!l&&h)return a(o,!0);if(s)return s(o,!0);var d=new Error("Cannot find module '"+o+"'");throw d.code="MODULE_NOT_FOUND",d}var f=n[o]={exports:{}};e[o][0].call(f.exports,function(t){return i(e[o][1][t]||t)},f,f.exports,t,e,n,r)}return n[o].exports}for(var s="function"==typeof a&&a,o=0;o<r.length;o++)i(r[o]);return i}return t}()({1:[function(t,e,n){"use strict";var a=t("pako/lib/deflate.js");e.exports=function(t){return a.deflateRaw(t,{level:9,to:"string"})}},{"pako/lib/deflate.js":4}],2:[function(t,e,n){"use strict";function a(t){return t<10?String.fromCharCode(48+t):(t-=10)<26?String.fromCharCode(65+t):(t-=26)<26?String.fromCharCode(97+t):(t-=26,0===t?"-":1===t?"_":"?")}function r(t,e,n){var r=t>>2,i=(3&t)<<4|e>>4,s=(15&e)<<2|n>>6,o=63&n,l="";return l+=a(63&r),l+=a(63&i),l+=a(63&s),l+=a(63&o)}e.exports=function(t){for(var e="",n=0;n<t.length;n+=3)n+2===t.length?e+=r(t.charCodeAt(n),t.charCodeAt(n+1),0):n+1===t.length?e+=r(t.charCodeAt(n),0,0):e+=r(t.charCodeAt(n),t.charCodeAt(n+1),t.charCodeAt(n+2));return e}},{}],3:[function(t,e,n){"use strict";var a=t("./deflate"),r=t("./encode64");e.exports.encode=function(t){var e=a(t);return r(e)}},{"./deflate":1,"./encode64":2}],4:[function(t,e,n){"use strict";function a(t){if(!(this instanceof a))return new a(t);this.options=l.assign({level:_,method:p,chunkSize:16384,windowBits:15,memLevel:8,strategy:g,to:""},t||{});var e=this.options;e.raw&&e.windowBits>0?e.windowBits=-e.windowBits:e.gzip&&e.windowBits>0&&e.windowBits<16&&(e.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new f,this.strm.avail_out=0;var n=o.deflateInit2(this.strm,e.level,e.method,e.windowBits,e.memLevel,e.strategy);if(n!==c)throw new Error(d[n]);if(e.header&&o.deflateSetHeader(this.strm,e.header),e.dictionary){var r;if(r="string"==typeof e.dictionary?h.string2buf(e.dictionary):"[object ArrayBuffer]"===u.call(e.dictionary)?new Uint8Array(e.dictionary):e.dictionary,(n=o.deflateSetDictionary(this.strm,r))!==c)throw new Error(d[n]);this._dict_set=!0}}function r(t,e){var n=new a(e);if(n.push(t,!0),n.err)throw n.msg||d[n.err];return n.result}function i(t,e){return e=e||{},e.raw=!0,r(t,e)}function s(t,e){return e=e||{},e.gzip=!0,r(t,e)}var o=t("./zlib/deflate"),l=t("./utils/common"),h=t("./utils/strings"),d=t("./zlib/messages"),f=t("./zlib/zstream"),u=Object.prototype.toString,c=0,_=-1,g=0,p=8;a.prototype.push=function(t,e){var n,a,r=this.strm,i=this.options.chunkSize;if(this.ended)return!1;a=e===~~e?e:!0===e?4:0,"string"==typeof t?r.input=h.string2buf(t):"[object ArrayBuffer]"===u.call(t)?r.input=new Uint8Array(t):r.input=t,r.next_in=0,r.avail_in=r.input.length;do{if(0===r.avail_out&&(r.output=new l.Buf8(i),r.next_out=0,r.avail_out=i),1!==(n=o.deflate(r,a))&&n!==c)return this.onEnd(n),this.ended=!0,!1;0!==r.avail_out&&(0!==r.avail_in||4!==a&&2!==a)||("string"===this.options.to?this.onData(h.buf2binstring(l.shrinkBuf(r.output,r.next_out))):this.onData(l.shrinkBuf(r.output,r.next_out)))}while((r.avail_in>0||0===r.avail_out)&&1!==n);return 4===a?(n=o.deflateEnd(this.strm),this.onEnd(n),this.ended=!0,n===c):2!==a||(this.onEnd(c),r.avail_out=0,!0)},a.prototype.onData=function(t){this.chunks.push(t)},a.prototype.onEnd=function(t){t===c&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=l.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg},n.Deflate=a,n.deflate=r,n.deflateRaw=i,n.gzip=s},{"./utils/common":5,"./utils/strings":6,"./zlib/deflate":9,"./zlib/messages":10,"./zlib/zstream":12}],5:[function(t,e,n){"use strict";function a(t,e){return Object.prototype.hasOwnProperty.call(t,e)}var r="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;n.assign=function(t){for(var e=Array.prototype.slice.call(arguments,1);e.length;){var n=e.shift();if(n){if("object"!=typeof n)throw new TypeError(n+"must be non-object");for(var r in n)a(n,r)&&(t[r]=n[r])}}return t},n.shrinkBuf=function(t,e){return t.length===e?t:t.subarray?t.subarray(0,e):(t.length=e,t)};var i={arraySet:function(t,e,n,a,r){if(e.subarray&&t.subarray)return void t.set(e.subarray(n,n+a),r);for(var i=0;i<a;i++)t[r+i]=e[n+i]},flattenChunks:function(t){var e,n,a,r,i,s;for(a=0,e=0,n=t.length;e<n;e++)a+=t[e].length;for(s=new Uint8Array(a),r=0,e=0,n=t.length;e<n;e++)i=t[e],s.set(i,r),r+=i.length;return s}},s={arraySet:function(t,e,n,a,r){for(var i=0;i<a;i++)t[r+i]=e[n+i]},flattenChunks:function(t){return[].concat.apply([],t)}};n.setTyped=function(t){t?(n.Buf8=Uint8Array,n.Buf16=Uint16Array,n.Buf32=Int32Array,n.assign(n,i)):(n.Buf8=Array,n.Buf16=Array,n.Buf32=Array,n.assign(n,s))},n.setTyped(r)},{}],6:[function(t,e,n){"use strict";function a(t,e){if(e<65534&&(t.subarray&&s||!t.subarray&&i))return String.fromCharCode.apply(null,r.shrinkBuf(t,e));for(var n="",a=0;a<e;a++)n+=String.fromCharCode(t[a]);return n}var r=t("./common"),i=!0,s=!0;try{String.fromCharCode.apply(null,[0])}catch(t){i=!1}try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(t){s=!1}for(var o=new r.Buf8(256),l=0;l<256;l++)o[l]=l>=252?6:l>=248?5:l>=240?4:l>=224?3:l>=192?2:1;o[254]=o[254]=1,n.string2buf=function(t){var e,n,a,i,s,o=t.length,l=0;for(i=0;i<o;i++)n=t.charCodeAt(i),55296==(64512&n)&&i+1<o&&56320==(64512&(a=t.charCodeAt(i+1)))&&(n=65536+(n-55296<<10)+(a-56320),i++),l+=n<128?1:n<2048?2:n<65536?3:4;for(e=new r.Buf8(l),s=0,i=0;s<l;i++)n=t.charCodeAt(i),55296==(64512&n)&&i+1<o&&56320==(64512&(a=t.charCodeAt(i+1)))&&(n=65536+(n-55296<<10)+(a-56320),i++),n<128?e[s++]=n:n<2048?(e[s++]=192|n>>>6,e[s++]=128|63&n):n<65536?(e[s++]=224|n>>>12,e[s++]=128|n>>>6&63,e[s++]=128|63&n):(e[s++]=240|n>>>18,e[s++]=128|n>>>12&63,e[s++]=128|n>>>6&63,e[s++]=128|63&n);return e},n.buf2binstring=function(t){return a(t,t.length)},n.binstring2buf=function(t){for(var e=new r.Buf8(t.length),n=0,a=e.length;n<a;n++)e[n]=t.charCodeAt(n);return e},n.buf2string=function(t,e){var n,r,i,s,l=e||t.length,h=new Array(2*l);for(r=0,n=0;n<l;)if((i=t[n++])<128)h[r++]=i;else if((s=o[i])>4)h[r++]=65533,n+=s-1;else{for(i&=2===s?31:3===s?15:7;s>1&&n<l;)i=i<<6|63&t[n++],s--;s>1?h[r++]=65533:i<65536?h[r++]=i:(i-=65536,h[r++]=55296|i>>10&1023,h[r++]=56320|1023&i)}return a(h,r)},n.utf8border=function(t,e){var n;for(e=e||t.length,e>t.length&&(e=t.length),n=e-1;n>=0&&128==(192&t[n]);)n--;return n<0?e:0===n?e:n+o[t[n]]>e?n:e}},{"./common":5}],7:[function(t,e,n){"use strict";function a(t,e,n,a){for(var r=65535&t|0,i=t>>>16&65535|0,s=0;0!==n;){s=n>2e3?2e3:n,n-=s;do{r=r+e[a++]|0,i=i+r|0}while(--s);r%=65521,i%=65521}return r|i<<16|0}e.exports=a},{}],8:[function(t,e,n){"use strict";function a(t,e,n,a){var i=r,s=a+n;t^=-1;for(var o=a;o<s;o++)t=t>>>8^i[255&(t^e[o])];return-1^t}var r=function(){for(var t,e=[],n=0;n<256;n++){t=n;for(var a=0;a<8;a++)t=1&t?3988292384^t>>>1:t>>>1;e[n]=t}return e}();e.exports=a},{}],9:[function(t,e,n){"use strict";function a(t,e){return t.msg=D[e],e}function r(t){return(t<<1)-(t>4?9:0)}function i(t){for(var e=t.length;--e>=0;)t[e]=0}function s(t){var e=t.state,n=e.pending;n>t.avail_out&&(n=t.avail_out),0!==n&&(O.arraySet(t.output,e.pending_buf,e.pending_out,n,t.next_out),t.next_out+=n,e.pending_out+=n,t.total_out+=n,t.avail_out-=n,e.pending-=n,0===e.pending&&(e.pending_out=0))}function o(t,e){Z._tr_flush_block(t,t.block_start>=0?t.block_start:-1,t.strstart-t.block_start,e),t.block_start=t.strstart,s(t.strm)}function l(t,e){t.pending_buf[t.pending++]=e}function h(t,e){t.pending_buf[t.pending++]=e>>>8&255,t.pending_buf[t.pending++]=255&e}function d(t,e,n,a){var r=t.avail_in;return r>a&&(r=a),0===r?0:(t.avail_in-=r,O.arraySet(e,t.input,t.next_in,r,n),1===t.state.wrap?t.adler=N(t.adler,e,r,n):2===t.state.wrap&&(t.adler=R(t.adler,e,r,n)),t.next_in+=r,t.total_in+=r,r)}function f(t,e){var n,a,r=t.max_chain_length,i=t.strstart,s=t.prev_length,o=t.nice_match,l=t.strstart>t.w_size-ht?t.strstart-(t.w_size-ht):0,h=t.window,d=t.w_mask,f=t.prev,u=t.strstart+lt,c=h[i+s-1],_=h[i+s];t.prev_length>=t.good_match&&(r>>=2),o>t.lookahead&&(o=t.lookahead);do{if(n=e,h[n+s]===_&&h[n+s-1]===c&&h[n]===h[i]&&h[++n]===h[i+1]){i+=2,n++;do{}while(h[++i]===h[++n]&&h[++i]===h[++n]&&h[++i]===h[++n]&&h[++i]===h[++n]&&h[++i]===h[++n]&&h[++i]===h[++n]&&h[++i]===h[++n]&&h[++i]===h[++n]&&i<u);if(a=lt-(u-i),i=u-lt,a>s){if(t.match_start=e,s=a,a>=o)break;c=h[i+s-1],_=h[i+s]}}}while((e=f[e&d])>l&&0!=--r);return s<=t.lookahead?s:t.lookahead}function u(t){var e,n,a,r,i,s=t.w_size;do{if(r=t.window_size-t.lookahead-t.strstart,t.strstart>=s+(s-ht)){O.arraySet(t.window,t.window,s,s,0),t.match_start-=s,t.strstart-=s,t.block_start-=s,n=t.hash_size,e=n;do{a=t.head[--e],t.head[e]=a>=s?a-s:0}while(--n);n=s,e=n;do{a=t.prev[--e],t.prev[e]=a>=s?a-s:0}while(--n);r+=s}if(0===t.strm.avail_in)break;if(n=d(t.strm,t.window,t.strstart+t.lookahead,r),t.lookahead+=n,t.lookahead+t.insert>=ot)for(i=t.strstart-t.insert,t.ins_h=t.window[i],t.ins_h=(t.ins_h<<t.hash_shift^t.window[i+1])&t.hash_mask;t.insert&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[i+ot-1])&t.hash_mask,t.prev[i&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=i,i++,t.insert--,!(t.lookahead+t.insert<ot)););}while(t.lookahead<ht&&0!==t.strm.avail_in)}function c(t,e){var n=65535;for(n>t.pending_buf_size-5&&(n=t.pending_buf_size-5);;){if(t.lookahead<=1){if(u(t),0===t.lookahead&&e===I)return bt;if(0===t.lookahead)break}t.strstart+=t.lookahead,t.lookahead=0;var a=t.block_start+n;if((0===t.strstart||t.strstart>=a)&&(t.lookahead=t.strstart-a,t.strstart=a,o(t,!1),0===t.strm.avail_out))return bt;if(t.strstart-t.block_start>=t.w_size-ht&&(o(t,!1),0===t.strm.avail_out))return bt}return t.insert=0,e===j?(o(t,!0),0===t.strm.avail_out?vt:kt):(t.strstart>t.block_start&&(o(t,!1),t.strm.avail_out),bt)}function _(t,e){for(var n,a;;){if(t.lookahead<ht){if(u(t),t.lookahead<ht&&e===I)return bt;if(0===t.lookahead)break}if(n=0,t.lookahead>=ot&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+ot-1])&t.hash_mask,n=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),0!==n&&t.strstart-n<=t.w_size-ht&&(t.match_length=f(t,n)),t.match_length>=ot)if(a=Z._tr_tally(t,t.strstart-t.match_start,t.match_length-ot),t.lookahead-=t.match_length,t.match_length<=t.max_lazy_match&&t.lookahead>=ot){t.match_length--;do{t.strstart++,t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+ot-1])&t.hash_mask,n=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart}while(0!=--t.match_length);t.strstart++}else t.strstart+=t.match_length,t.match_length=0,t.ins_h=t.window[t.strstart],t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+1])&t.hash_mask;else a=Z._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++;if(a&&(o(t,!1),0===t.strm.avail_out))return bt}return t.insert=t.strstart<ot-1?t.strstart:ot-1,e===j?(o(t,!0),0===t.strm.avail_out?vt:kt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?bt:wt}function g(t,e){for(var n,a,r;;){if(t.lookahead<ht){if(u(t),t.lookahead<ht&&e===I)return bt;if(0===t.lookahead)break}if(n=0,t.lookahead>=ot&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+ot-1])&t.hash_mask,n=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),t.prev_length=t.match_length,t.prev_match=t.match_start,t.match_length=ot-1,0!==n&&t.prev_length<t.max_lazy_match&&t.strstart-n<=t.w_size-ht&&(t.match_length=f(t,n),t.match_length<=5&&(t.strategy===Y||t.match_length===ot&&t.strstart-t.match_start>4096)&&(t.match_length=ot-1)),t.prev_length>=ot&&t.match_length<=t.prev_length){r=t.strstart+t.lookahead-ot,a=Z._tr_tally(t,t.strstart-1-t.prev_match,t.prev_length-ot),t.lookahead-=t.prev_length-1,t.prev_length-=2;do{++t.strstart<=r&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+ot-1])&t.hash_mask,n=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart)}while(0!=--t.prev_length);if(t.match_available=0,t.match_length=ot-1,t.strstart++,a&&(o(t,!1),0===t.strm.avail_out))return bt}else if(t.match_available){if(a=Z._tr_tally(t,0,t.window[t.strstart-1]),a&&o(t,!1),t.strstart++,t.lookahead--,0===t.strm.avail_out)return bt}else t.match_available=1,t.strstart++,t.lookahead--}return t.match_available&&(a=Z._tr_tally(t,0,t.window[t.strstart-1]),t.match_available=0),t.insert=t.strstart<ot-1?t.strstart:ot-1,e===j?(o(t,!0),0===t.strm.avail_out?vt:kt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?bt:wt}function p(t,e){for(var n,a,r,i,s=t.window;;){if(t.lookahead<=lt){if(u(t),t.lookahead<=lt&&e===I)return bt;if(0===t.lookahead)break}if(t.match_length=0,t.lookahead>=ot&&t.strstart>0&&(r=t.strstart-1,(a=s[r])===s[++r]&&a===s[++r]&&a===s[++r])){i=t.strstart+lt;do{}while(a===s[++r]&&a===s[++r]&&a===s[++r]&&a===s[++r]&&a===s[++r]&&a===s[++r]&&a===s[++r]&&a===s[++r]&&r<i);t.match_length=lt-(i-r),t.match_length>t.lookahead&&(t.match_length=t.lookahead)}if(t.match_length>=ot?(n=Z._tr_tally(t,1,t.match_length-ot),t.lookahead-=t.match_length,t.strstart+=t.match_length,t.match_length=0):(n=Z._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++),n&&(o(t,!1),0===t.strm.avail_out))return bt}return t.insert=0,e===j?(o(t,!0),0===t.strm.avail_out?vt:kt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?bt:wt}function m(t,e){for(var n;;){if(0===t.lookahead&&(u(t),0===t.lookahead)){if(e===I)return bt;break}if(t.match_length=0,n=Z._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++,n&&(o(t,!1),0===t.strm.avail_out))return bt}return t.insert=0,e===j?(o(t,!0),0===t.strm.avail_out?vt:kt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?bt:wt}function b(t,e,n,a,r){this.good_length=t,this.max_lazy=e,this.nice_length=n,this.max_chain=a,this.func=r}function w(t){t.window_size=2*t.w_size,i(t.head),t.max_lazy_match=E[t.level].max_lazy,t.good_match=E[t.level].good_length,t.nice_match=E[t.level].nice_length,t.max_chain_length=E[t.level].max_chain,t.strstart=0,t.block_start=0,t.lookahead=0,t.insert=0,t.match_length=t.prev_length=ot-1,t.match_available=0,t.ins_h=0}function v(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=Q,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new O.Buf16(2*it),this.dyn_dtree=new O.Buf16(2*(2*at+1)),this.bl_tree=new O.Buf16(2*(2*rt+1)),i(this.dyn_ltree),i(this.dyn_dtree),i(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new O.Buf16(st+1),this.heap=new O.Buf16(2*nt+1),i(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new O.Buf16(2*nt+1),i(this.depth),this.l_buf=0,this.lit_bufsize=0,this.last_lit=0,this.d_buf=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}function k(t){var e;return t&&t.state?(t.total_in=t.total_out=0,t.data_type=J,e=t.state,e.pending=0,e.pending_out=0,e.wrap<0&&(e.wrap=-e.wrap),e.status=e.wrap?ft:pt,t.adler=2===e.wrap?0:1,e.last_flush=I,Z._tr_init(e),L):a(t,M)}function y(t){var e=k(t);return e===L&&w(t.state),e}function x(t,e){return t&&t.state?2!==t.state.wrap?M:(t.state.gzhead=e,L):M}function z(t,e,n,r,i,s){if(!t)return M;var o=1;if(e===K&&(e=6),r<0?(o=0,r=-r):r>15&&(o=2,r-=16),i<1||i>V||n!==Q||r<8||r>15||e<0||e>9||s<0||s>G)return a(t,M);8===r&&(r=9);var l=new v;return t.state=l,l.strm=t,l.wrap=o,l.gzhead=null,l.w_bits=r,l.w_size=1<<l.w_bits,l.w_mask=l.w_size-1,l.hash_bits=i+7,l.hash_size=1<<l.hash_bits,l.hash_mask=l.hash_size-1,l.hash_shift=~~((l.hash_bits+ot-1)/ot),l.window=new O.Buf8(2*l.w_size),l.head=new O.Buf16(l.hash_size),l.prev=new O.Buf16(l.w_size),l.lit_bufsize=1<<i+6,l.pending_buf_size=4*l.lit_bufsize,l.pending_buf=new O.Buf8(l.pending_buf_size),l.d_buf=1*l.lit_bufsize,l.l_buf=3*l.lit_bufsize,l.level=e,l.strategy=s,l.method=n,y(t)}function B(t,e){return z(t,e,Q,tt,et,X)}function C(t,e){var n,o,d,f;if(!t||!t.state||e>F||e<0)return t?a(t,M):M;if(o=t.state,!t.output||!t.input&&0!==t.avail_in||o.status===mt&&e!==j)return a(t,0===t.avail_out?W:M);if(o.strm=t,n=o.last_flush,o.last_flush=e,o.status===ft)if(2===o.wrap)t.adler=0,l(o,31),l(o,139),l(o,8),o.gzhead?(l(o,(o.gzhead.text?1:0)+(o.gzhead.hcrc?2:0)+(o.gzhead.extra?4:0)+(o.gzhead.name?8:0)+(o.gzhead.comment?16:0)),l(o,255&o.gzhead.time),l(o,o.gzhead.time>>8&255),l(o,o.gzhead.time>>16&255),l(o,o.gzhead.time>>24&255),l(o,9===o.level?2:o.strategy>=$||o.level<2?4:0),l(o,255&o.gzhead.os),o.gzhead.extra&&o.gzhead.extra.length&&(l(o,255&o.gzhead.extra.length),l(o,o.gzhead.extra.length>>8&255)),o.gzhead.hcrc&&(t.adler=R(t.adler,o.pending_buf,o.pending,0)),o.gzindex=0,o.status=ut):(l(o,0),l(o,0),l(o,0),l(o,0),l(o,0),l(o,9===o.level?2:o.strategy>=$||o.level<2?4:0),l(o,yt),o.status=pt);else{var u=Q+(o.w_bits-8<<4)<<8,c=-1;c=o.strategy>=$||o.level<2?0:o.level<6?1:6===o.level?2:3,u|=c<<6,0!==o.strstart&&(u|=dt),u+=31-u%31,o.status=pt,h(o,u),0!==o.strstart&&(h(o,t.adler>>>16),h(o,65535&t.adler)),t.adler=1}if(o.status===ut)if(o.gzhead.extra){for(d=o.pending;o.gzindex<(65535&o.gzhead.extra.length)&&(o.pending!==o.pending_buf_size||(o.gzhead.hcrc&&o.pending>d&&(t.adler=R(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending!==o.pending_buf_size));)l(o,255&o.gzhead.extra[o.gzindex]),o.gzindex++;o.gzhead.hcrc&&o.pending>d&&(t.adler=R(t.adler,o.pending_buf,o.pending-d,d)),o.gzindex===o.gzhead.extra.length&&(o.gzindex=0,o.status=ct)}else o.status=ct;if(o.status===ct)if(o.gzhead.name){d=o.pending;do{if(o.pending===o.pending_buf_size&&(o.gzhead.hcrc&&o.pending>d&&(t.adler=R(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending===o.pending_buf_size)){f=1;break}f=o.gzindex<o.gzhead.name.length?255&o.gzhead.name.charCodeAt(o.gzindex++):0,l(o,f)}while(0!==f);o.gzhead.hcrc&&o.pending>d&&(t.adler=R(t.adler,o.pending_buf,o.pending-d,d)),0===f&&(o.gzindex=0,o.status=_t)}else o.status=_t;if(o.status===_t)if(o.gzhead.comment){d=o.pending;do{if(o.pending===o.pending_buf_size&&(o.gzhead.hcrc&&o.pending>d&&(t.adler=R(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending===o.pending_buf_size)){f=1;break}f=o.gzindex<o.gzhead.comment.length?255&o.gzhead.comment.charCodeAt(o.gzindex++):0,l(o,f)}while(0!==f);o.gzhead.hcrc&&o.pending>d&&(t.adler=R(t.adler,o.pending_buf,o.pending-d,d)),0===f&&(o.status=gt)}else o.status=gt;if(o.status===gt&&(o.gzhead.hcrc?(o.pending+2>o.pending_buf_size&&s(t),o.pending+2<=o.pending_buf_size&&(l(o,255&t.adler),l(o,t.adler>>8&255),t.adler=0,o.status=pt)):o.status=pt),0!==o.pending){if(s(t),0===t.avail_out)return o.last_flush=-1,L}else if(0===t.avail_in&&r(e)<=r(n)&&e!==j)return a(t,W);if(o.status===mt&&0!==t.avail_in)return a(t,W);if(0!==t.avail_in||0!==o.lookahead||e!==I&&o.status!==mt){var _=o.strategy===$?m(o,e):o.strategy===q?p(o,e):E[o.level].func(o,e);if(_!==vt&&_!==kt||(o.status=mt),_===bt||_===vt)return 0===t.avail_out&&(o.last_flush=-1),L;if(_===wt&&(e===U?Z._tr_align(o):e!==F&&(Z._tr_stored_block(o,0,0,!1),e===T&&(i(o.head),0===o.lookahead&&(o.strstart=0,o.block_start=0,o.insert=0))),s(t),0===t.avail_out))return o.last_flush=-1,L}return e!==j?L:o.wrap<=0?H:(2===o.wrap?(l(o,255&t.adler),l(o,t.adler>>8&255),l(o,t.adler>>16&255),l(o,t.adler>>24&255),l(o,255&t.total_in),l(o,t.total_in>>8&255),l(o,t.total_in>>16&255),l(o,t.total_in>>24&255)):(h(o,t.adler>>>16),h(o,65535&t.adler)),s(t),o.wrap>0&&(o.wrap=-o.wrap),0!==o.pending?L:H)}function A(t){var e;return t&&t.state?(e=t.state.status)!==ft&&e!==ut&&e!==ct&&e!==_t&&e!==gt&&e!==pt&&e!==mt?a(t,M):(t.state=null,e===pt?a(t,P):L):M}function S(t,e){var n,a,r,s,o,l,h,d,f=e.length;if(!t||!t.state)return M;if(n=t.state,2===(s=n.wrap)||1===s&&n.status!==ft||n.lookahead)return M;for(1===s&&(t.adler=N(t.adler,e,f,0)),n.wrap=0,f>=n.w_size&&(0===s&&(i(n.head),n.strstart=0,n.block_start=0,n.insert=0),d=new O.Buf8(n.w_size),O.arraySet(d,e,f-n.w_size,n.w_size,0),e=d,f=n.w_size),o=t.avail_in,l=t.next_in,h=t.input,t.avail_in=f,t.next_in=0,t.input=e,u(n);n.lookahead>=ot;){a=n.strstart,r=n.lookahead-(ot-1);do{n.ins_h=(n.ins_h<<n.hash_shift^n.window[a+ot-1])&n.hash_mask,n.prev[a&n.w_mask]=n.head[n.ins_h],n.head[n.ins_h]=a,a++}while(--r);n.strstart=a,n.lookahead=ot-1,u(n)}return n.strstart+=n.lookahead,n.block_start=n.strstart,n.insert=n.lookahead,n.lookahead=0,n.match_length=n.prev_length=ot-1,n.match_available=0,t.next_in=l,t.input=h,t.avail_in=o,n.wrap=s,L}var E,O=t("../utils/common"),Z=t("./trees"),N=t("./adler32"),R=t("./crc32"),D=t("./messages"),I=0,U=1,T=3,j=4,F=5,L=0,H=1,M=-2,P=-3,W=-5,K=-1,Y=1,$=2,q=3,G=4,X=0,J=2,Q=8,V=9,tt=15,et=8,nt=286,at=30,rt=19,it=2*nt+1,st=15,ot=3,lt=258,ht=lt+ot+1,dt=32,ft=42,ut=69,ct=73,_t=91,gt=103,pt=113,mt=666,bt=1,wt=2,vt=3,kt=4,yt=3;E=[new b(0,0,0,0,c),new b(4,4,8,4,_),new b(4,5,16,8,_),new b(4,6,32,32,_),new b(4,4,16,16,g),new b(8,16,32,32,g),new b(8,16,128,128,g),new b(8,32,128,256,g),new b(32,128,258,1024,g),new b(32,258,258,4096,g)],n.deflateInit=B,n.deflateInit2=z,n.deflateReset=y,n.deflateResetKeep=k,n.deflateSetHeader=x,n.deflate=C,n.deflateEnd=A,n.deflateSetDictionary=S,n.deflateInfo="pako deflate (from Nodeca project)"},{"../utils/common":5,"./adler32":7,"./crc32":8,"./messages":10,"./trees":11}],10:[function(t,e,n){"use strict";e.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],11:[function(t,e,n){"use strict";function a(t){for(var e=t.length;--e>=0;)t[e]=0}function r(t,e,n,a,r){this.static_tree=t,this.extra_bits=e,this.extra_base=n,this.elems=a,this.max_length=r,this.has_stree=t&&t.length}function i(t,e){this.dyn_tree=t,this.max_code=0,this.stat_desc=e}function s(t){return t<256?it[t]:it[256+(t>>>7)]}function o(t,e){t.pending_buf[t.pending++]=255&e,t.pending_buf[t.pending++]=e>>>8&255}function l(t,e,n){t.bi_valid>$-n?(t.bi_buf|=e<<t.bi_valid&65535,o(t,t.bi_buf),t.bi_buf=e>>$-t.bi_valid,t.bi_valid+=n-$):(t.bi_buf|=e<<t.bi_valid&65535,t.bi_valid+=n)}function h(t,e,n){l(t,n[2*e],n[2*e+1])}function d(t,e){var n=0;do{n|=1&t,t>>>=1,n<<=1}while(--e>0);return n>>>1}function f(t){16===t.bi_valid?(o(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):t.bi_valid>=8&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)}function u(t,e){var n,a,r,i,s,o,l=e.dyn_tree,h=e.max_code,d=e.stat_desc.static_tree,f=e.stat_desc.has_stree,u=e.stat_desc.extra_bits,c=e.stat_desc.extra_base,_=e.stat_desc.max_length,g=0;for(i=0;i<=Y;i++)t.bl_count[i]=0;for(l[2*t.heap[t.heap_max]+1]=0,n=t.heap_max+1;n<K;n++)a=t.heap[n],i=l[2*l[2*a+1]+1]+1,i>_&&(i=_,g++),l[2*a+1]=i,a>h||(t.bl_count[i]++,s=0,a>=c&&(s=u[a-c]),o=l[2*a],t.opt_len+=o*(i+s),f&&(t.static_len+=o*(d[2*a+1]+s)));if(0!==g){do{for(i=_-1;0===t.bl_count[i];)i--;t.bl_count[i]--,t.bl_count[i+1]+=2,t.bl_count[_]--,g-=2}while(g>0);for(i=_;0!==i;i--)for(a=t.bl_count[i];0!==a;)(r=t.heap[--n])>h||(l[2*r+1]!==i&&(t.opt_len+=(i-l[2*r+1])*l[2*r],l[2*r+1]=i),a--)}}function c(t,e,n){var a,r,i=new Array(Y+1),s=0;for(a=1;a<=Y;a++)i[a]=s=s+n[a-1]<<1;for(r=0;r<=e;r++){var o=t[2*r+1];0!==o&&(t[2*r]=d(i[o]++,o))}}function _(){var t,e,n,a,i,s=new Array(Y+1);for(n=0,a=0;a<L-1;a++)for(ot[a]=n,t=0;t<1<<V[a];t++)st[n++]=a;for(st[n-1]=a,i=0,a=0;a<16;a++)for(lt[a]=i,t=0;t<1<<tt[a];t++)it[i++]=a;for(i>>=7;a<P;a++)for(lt[a]=i<<7,t=0;t<1<<tt[a]-7;t++)it[256+i++]=a;for(e=0;e<=Y;e++)s[e]=0;for(t=0;t<=143;)at[2*t+1]=8,t++,s[8]++;for(;t<=255;)at[2*t+1]=9,t++,s[9]++;for(;t<=279;)at[2*t+1]=7,t++,s[7]++;for(;t<=287;)at[2*t+1]=8,t++,s[8]++;for(c(at,M+1,s),t=0;t<P;t++)rt[2*t+1]=5,rt[2*t]=d(t,5);ht=new r(at,V,H+1,M,Y),dt=new r(rt,tt,0,P,Y),ft=new r(new Array(0),et,0,W,q)}function g(t){var e;for(e=0;e<M;e++)t.dyn_ltree[2*e]=0;for(e=0;e<P;e++)t.dyn_dtree[2*e]=0;for(e=0;e<W;e++)t.bl_tree[2*e]=0;t.dyn_ltree[2*G]=1,t.opt_len=t.static_len=0,t.last_lit=t.matches=0}function p(t){t.bi_valid>8?o(t,t.bi_buf):t.bi_valid>0&&(t.pending_buf[t.pending++]=t.bi_buf),t.bi_buf=0,t.bi_valid=0}function m(t,e,n,a){p(t),a&&(o(t,n),o(t,~n)),N.arraySet(t.pending_buf,t.window,e,n,t.pending),t.pending+=n}function b(t,e,n,a){var r=2*e,i=2*n;return t[r]<t[i]||t[r]===t[i]&&a[e]<=a[n]}function w(t,e,n){for(var a=t.heap[n],r=n<<1;r<=t.heap_len&&(r<t.heap_len&&b(e,t.heap[r+1],t.heap[r],t.depth)&&r++,!b(e,a,t.heap[r],t.depth));)t.heap[n]=t.heap[r],n=r,r<<=1;t.heap[n]=a}function v(t,e,n){var a,r,i,o,d=0;if(0!==t.last_lit)do{a=t.pending_buf[t.d_buf+2*d]<<8|t.pending_buf[t.d_buf+2*d+1],r=t.pending_buf[t.l_buf+d],d++,0===a?h(t,r,e):(i=st[r],h(t,i+H+1,e),o=V[i],0!==o&&(r-=ot[i],l(t,r,o)),a--,i=s(a),h(t,i,n),0!==(o=tt[i])&&(a-=lt[i],l(t,a,o)))}while(d<t.last_lit);h(t,G,e)}function k(t,e){var n,a,r,i=e.dyn_tree,s=e.stat_desc.static_tree,o=e.stat_desc.has_stree,l=e.stat_desc.elems,h=-1;for(t.heap_len=0,t.heap_max=K,n=0;n<l;n++)0!==i[2*n]?(t.heap[++t.heap_len]=h=n,t.depth[n]=0):i[2*n+1]=0;for(;t.heap_len<2;)r=t.heap[++t.heap_len]=h<2?++h:0,i[2*r]=1,t.depth[r]=0,t.opt_len--,o&&(t.static_len-=s[2*r+1]);for(e.max_code=h,n=t.heap_len>>1;n>=1;n--)w(t,i,n);r=l;do{n=t.heap[1],t.heap[1]=t.heap[t.heap_len--],w(t,i,1),a=t.heap[1],t.heap[--t.heap_max]=n,t.heap[--t.heap_max]=a,i[2*r]=i[2*n]+i[2*a],t.depth[r]=(t.depth[n]>=t.depth[a]?t.depth[n]:t.depth[a])+1,i[2*n+1]=i[2*a+1]=r,t.heap[1]=r++,w(t,i,1)}while(t.heap_len>=2);t.heap[--t.heap_max]=t.heap[1],u(t,e),c(i,h,t.bl_count)}function y(t,e,n){var a,r,i=-1,s=e[1],o=0,l=7,h=4;for(0===s&&(l=138,h=3),e[2*(n+1)+1]=65535,a=0;a<=n;a++)r=s,s=e[2*(a+1)+1],++o<l&&r===s||(o<h?t.bl_tree[2*r]+=o:0!==r?(r!==i&&t.bl_tree[2*r]++,t.bl_tree[2*X]++):o<=10?t.bl_tree[2*J]++:t.bl_tree[2*Q]++,o=0,i=r,0===s?(l=138,h=3):r===s?(l=6,h=3):(l=7,h=4))}function x(t,e,n){var a,r,i=-1,s=e[1],o=0,d=7,f=4;for(0===s&&(d=138,f=3),a=0;a<=n;a++)if(r=s,s=e[2*(a+1)+1],!(++o<d&&r===s)){if(o<f)do{h(t,r,t.bl_tree)}while(0!=--o);else 0!==r?(r!==i&&(h(t,r,t.bl_tree),o--),h(t,X,t.bl_tree),l(t,o-3,2)):o<=10?(h(t,J,t.bl_tree),l(t,o-3,3)):(h(t,Q,t.bl_tree),l(t,o-11,7));o=0,i=r,0===s?(d=138,f=3):r===s?(d=6,f=3):(d=7,f=4)}}function z(t){var e;for(y(t,t.dyn_ltree,t.l_desc.max_code),y(t,t.dyn_dtree,t.d_desc.max_code),k(t,t.bl_desc),e=W-1;e>=3&&0===t.bl_tree[2*nt[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e}function B(t,e,n,a){var r;for(l(t,e-257,5),l(t,n-1,5),l(t,a-4,4),r=0;r<a;r++)l(t,t.bl_tree[2*nt[r]+1],3);x(t,t.dyn_ltree,e-1),x(t,t.dyn_dtree,n-1)}function C(t){var e,n=4093624447;for(e=0;e<=31;e++,n>>>=1)if(1&n&&0!==t.dyn_ltree[2*e])return D;if(0!==t.dyn_ltree[18]||0!==t.dyn_ltree[20]||0!==t.dyn_ltree[26])return I;for(e=32;e<H;e++)if(0!==t.dyn_ltree[2*e])return I;return D}function A(t){ut||(_(),ut=!0),t.l_desc=new i(t.dyn_ltree,ht),t.d_desc=new i(t.dyn_dtree,dt),t.bl_desc=new i(t.bl_tree,ft),t.bi_buf=0,t.bi_valid=0,g(t)}function S(t,e,n,a){l(t,(T<<1)+(a?1:0),3),m(t,e,n,!0)}function E(t){l(t,j<<1,3),h(t,G,at),f(t)}function O(t,e,n,a){var r,i,s=0;t.level>0?(t.strm.data_type===U&&(t.strm.data_type=C(t)),k(t,t.l_desc),k(t,t.d_desc),s=z(t),r=t.opt_len+3+7>>>3,(i=t.static_len+3+7>>>3)<=r&&(r=i)):r=i=n+5,n+4<=r&&-1!==e?S(t,e,n,a):t.strategy===R||i===r?(l(t,(j<<1)+(a?1:0),3),v(t,at,rt)):(l(t,(F<<1)+(a?1:0),3),B(t,t.l_desc.max_code+1,t.d_desc.max_code+1,s+1),v(t,t.dyn_ltree,t.dyn_dtree)),g(t),a&&p(t)}function Z(t,e,n){return t.pending_buf[t.d_buf+2*t.last_lit]=e>>>8&255,t.pending_buf[t.d_buf+2*t.last_lit+1]=255&e,t.pending_buf[t.l_buf+t.last_lit]=255&n,t.last_lit++,0===e?t.dyn_ltree[2*n]++:(t.matches++,e--,t.dyn_ltree[2*(st[n]+H+1)]++,t.dyn_dtree[2*s(e)]++),t.last_lit===t.lit_bufsize-1}var N=t("../utils/common"),R=4,D=0,I=1,U=2,T=0,j=1,F=2,L=29,H=256,M=H+1+L,P=30,W=19,K=2*M+1,Y=15,$=16,q=7,G=256,X=16,J=17,Q=18,V=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],tt=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],et=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],nt=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],at=new Array(2*(M+2));a(at);var rt=new Array(2*P);a(rt);var it=new Array(512);a(it);var st=new Array(256);a(st);var ot=new Array(L);a(ot);var lt=new Array(P);a(lt);var ht,dt,ft,ut=!1;n._tr_init=A,n._tr_stored_block=S,n._tr_flush_block=O,n._tr_tally=Z,n._tr_align=E},{"../utils/common":5}],12:[function(t,e,n){"use strict";function a(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}e.exports=a},{}]},{},[3])(3)})},function(t,e,n){var a,a;!function(e){t.exports=e()}(function(){return function(){function t(e,n,r){function i(o,l){if(!n[o]){if(!e[o]){var h="function"==typeof a&&a;if(!l&&h)return a(o,!0);if(s)return s(o,!0);var d=new Error("Cannot find module '"+o+"'");throw d.code="MODULE_NOT_FOUND",d}var f=n[o]={exports:{}};e[o][0].call(f.exports,function(t){return i(e[o][1][t]||t)},f,f.exports,t,e,n,r)}return n[o].exports}for(var s="function"==typeof a&&a,o=0;o<r.length;o++)i(r[o]);return i}return t}()({1:[function(t,e,n){"use strict";var a=t("pako/lib/inflate.js");e.exports=function(t){return a.inflateRaw(t,{to:"string"})}},{"pako/lib/inflate.js":4}],2:[function(t,e,n){"use strict";function a(t){var e=t.charCodeAt(0);return"_"===t?63:"-"===t?62:e>=97?e-61:e>=65?e-55:e>=48?e-48:"?"}function r(t){var e=a(t[0]),n=a(t[1]),r=a(t[2]);return[e<<2|n>>4&63,n<<4&240|r>>2&15,r<<6&192|63&a(t[3])]}e.exports=function(t){var e="",n=0;for(n=0;n<t.length;n+=4){var a=r(t.substring(n,n+4));e+=String.fromCharCode(a[0]),e+=String.fromCharCode(a[1]),e+=String.fromCharCode(a[2])}return e}},{}],3:[function(t,e,n){"use strict";var a=t("./inflate"),r=t("./decode64");e.exports.decode=function(t){var e=r(t);return a(e)}},{"./decode64":2,"./inflate":1}],4:[function(t,e,n){"use strict";function a(t){if(!(this instanceof a))return new a(t);this.options=o.assign({chunkSize:16384,windowBits:0,to:""},t||{});var e=this.options;e.raw&&e.windowBits>=0&&e.windowBits<16&&(e.windowBits=-e.windowBits,0===e.windowBits&&(e.windowBits=-15)),!(e.windowBits>=0&&e.windowBits<16)||t&&t.windowBits||(e.windowBits+=32),e.windowBits>15&&e.windowBits<48&&0==(15&e.windowBits)&&(e.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new f,this.strm.avail_out=0;var n=s.inflateInit2(this.strm,e.windowBits);if(n!==h.Z_OK)throw new Error(d[n]);if(this.header=new u,s.inflateGetHeader(this.strm,this.header),e.dictionary&&("string"==typeof e.dictionary?e.dictionary=l.string2buf(e.dictionary):"[object ArrayBuffer]"===c.call(e.dictionary)&&(e.dictionary=new Uint8Array(e.dictionary)),e.raw&&(n=s.inflateSetDictionary(this.strm,e.dictionary))!==h.Z_OK))throw new Error(d[n])}function r(t,e){var n=new a(e);if(n.push(t,!0),n.err)throw n.msg||d[n.err];return n.result}function i(t,e){return e=e||{},e.raw=!0,r(t,e)}var s=t("./zlib/inflate"),o=t("./utils/common"),l=t("./utils/strings"),h=t("./zlib/constants"),d=t("./zlib/messages"),f=t("./zlib/zstream"),u=t("./zlib/gzheader"),c=Object.prototype.toString;a.prototype.push=function(t,e){var n,a,r,i,d,f=this.strm,u=this.options.chunkSize,_=this.options.dictionary,g=!1;if(this.ended)return!1;a=e===~~e?e:!0===e?h.Z_FINISH:h.Z_NO_FLUSH,"string"==typeof t?f.input=l.binstring2buf(t):"[object ArrayBuffer]"===c.call(t)?f.input=new Uint8Array(t):f.input=t,f.next_in=0,f.avail_in=f.input.length;do{if(0===f.avail_out&&(f.output=new o.Buf8(u),f.next_out=0,f.avail_out=u),n=s.inflate(f,h.Z_NO_FLUSH),n===h.Z_NEED_DICT&&_&&(n=s.inflateSetDictionary(this.strm,_)),n===h.Z_BUF_ERROR&&!0===g&&(n=h.Z_OK,g=!1),n!==h.Z_STREAM_END&&n!==h.Z_OK)return this.onEnd(n),this.ended=!0,!1;f.next_out&&(0!==f.avail_out&&n!==h.Z_STREAM_END&&(0!==f.avail_in||a!==h.Z_FINISH&&a!==h.Z_SYNC_FLUSH)||("string"===this.options.to?(r=l.utf8border(f.output,f.next_out),i=f.next_out-r,d=l.buf2string(f.output,r),f.next_out=i,f.avail_out=u-i,i&&o.arraySet(f.output,f.output,r,i,0),this.onData(d)):this.onData(o.shrinkBuf(f.output,f.next_out)))),0===f.avail_in&&0===f.avail_out&&(g=!0)}while((f.avail_in>0||0===f.avail_out)&&n!==h.Z_STREAM_END);return n===h.Z_STREAM_END&&(a=h.Z_FINISH),a===h.Z_FINISH?(n=s.inflateEnd(this.strm),this.onEnd(n),this.ended=!0,n===h.Z_OK):a!==h.Z_SYNC_FLUSH||(this.onEnd(h.Z_OK),f.avail_out=0,!0)},a.prototype.onData=function(t){this.chunks.push(t)},a.prototype.onEnd=function(t){t===h.Z_OK&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=o.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg},n.Inflate=a,n.inflate=r,n.inflateRaw=i,n.ungzip=r},{"./utils/common":5,"./utils/strings":6,"./zlib/constants":8,"./zlib/gzheader":10,"./zlib/inflate":12,"./zlib/messages":14,"./zlib/zstream":15}],5:[function(t,e,n){"use strict";function a(t,e){return Object.prototype.hasOwnProperty.call(t,e)}var r="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;n.assign=function(t){for(var e=Array.prototype.slice.call(arguments,1);e.length;){var n=e.shift();if(n){if("object"!=typeof n)throw new TypeError(n+"must be non-object");for(var r in n)a(n,r)&&(t[r]=n[r])}}return t},n.shrinkBuf=function(t,e){return t.length===e?t:t.subarray?t.subarray(0,e):(t.length=e,t)};var i={arraySet:function(t,e,n,a,r){if(e.subarray&&t.subarray)return void t.set(e.subarray(n,n+a),r);for(var i=0;i<a;i++)t[r+i]=e[n+i]},flattenChunks:function(t){var e,n,a,r,i,s;for(a=0,e=0,n=t.length;e<n;e++)a+=t[e].length;for(s=new Uint8Array(a),r=0,e=0,n=t.length;e<n;e++)i=t[e],s.set(i,r),r+=i.length;return s}},s={arraySet:function(t,e,n,a,r){for(var i=0;i<a;i++)t[r+i]=e[n+i]},flattenChunks:function(t){return[].concat.apply([],t)}};n.setTyped=function(t){t?(n.Buf8=Uint8Array,n.Buf16=Uint16Array,n.Buf32=Int32Array,n.assign(n,i)):(n.Buf8=Array,n.Buf16=Array,n.Buf32=Array,n.assign(n,s))},n.setTyped(r)},{}],6:[function(t,e,n){"use strict";function a(t,e){if(e<65534&&(t.subarray&&s||!t.subarray&&i))return String.fromCharCode.apply(null,r.shrinkBuf(t,e));for(var n="",a=0;a<e;a++)n+=String.fromCharCode(t[a]);return n}var r=t("./common"),i=!0,s=!0;try{String.fromCharCode.apply(null,[0])}catch(t){i=!1}try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(t){s=!1}for(var o=new r.Buf8(256),l=0;l<256;l++)o[l]=l>=252?6:l>=248?5:l>=240?4:l>=224?3:l>=192?2:1;o[254]=o[254]=1,n.string2buf=function(t){var e,n,a,i,s,o=t.length,l=0;for(i=0;i<o;i++)n=t.charCodeAt(i),55296==(64512&n)&&i+1<o&&56320==(64512&(a=t.charCodeAt(i+1)))&&(n=65536+(n-55296<<10)+(a-56320),i++),l+=n<128?1:n<2048?2:n<65536?3:4;for(e=new r.Buf8(l),s=0,i=0;s<l;i++)n=t.charCodeAt(i),55296==(64512&n)&&i+1<o&&56320==(64512&(a=t.charCodeAt(i+1)))&&(n=65536+(n-55296<<10)+(a-56320),i++),n<128?e[s++]=n:n<2048?(e[s++]=192|n>>>6,e[s++]=128|63&n):n<65536?(e[s++]=224|n>>>12,e[s++]=128|n>>>6&63,e[s++]=128|63&n):(e[s++]=240|n>>>18,e[s++]=128|n>>>12&63,e[s++]=128|n>>>6&63,e[s++]=128|63&n);return e},n.buf2binstring=function(t){return a(t,t.length)},n.binstring2buf=function(t){for(var e=new r.Buf8(t.length),n=0,a=e.length;n<a;n++)e[n]=t.charCodeAt(n);return e},n.buf2string=function(t,e){var n,r,i,s,l=e||t.length,h=new Array(2*l);for(r=0,n=0;n<l;)if((i=t[n++])<128)h[r++]=i;else if((s=o[i])>4)h[r++]=65533,n+=s-1;else{for(i&=2===s?31:3===s?15:7;s>1&&n<l;)i=i<<6|63&t[n++],s--;s>1?h[r++]=65533:i<65536?h[r++]=i:(i-=65536,h[r++]=55296|i>>10&1023,h[r++]=56320|1023&i)}return a(h,r)},n.utf8border=function(t,e){var n;for(e=e||t.length,e>t.length&&(e=t.length),n=e-1;n>=0&&128==(192&t[n]);)n--;return n<0?e:0===n?e:n+o[t[n]]>e?n:e}},{"./common":5}],7:[function(t,e,n){"use strict";function a(t,e,n,a){for(var r=65535&t|0,i=t>>>16&65535|0,s=0;0!==n;){s=n>2e3?2e3:n,n-=s;do{r=r+e[a++]|0,i=i+r|0}while(--s);r%=65521,i%=65521}return r|i<<16|0}e.exports=a},{}],8:[function(t,e,n){"use strict";e.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],9:[function(t,e,n){"use strict";function a(t,e,n,a){var i=r,s=a+n;t^=-1;for(var o=a;o<s;o++)t=t>>>8^i[255&(t^e[o])];return-1^t}var r=function(){for(var t,e=[],n=0;n<256;n++){t=n;for(var a=0;a<8;a++)t=1&t?3988292384^t>>>1:t>>>1;e[n]=t}return e}();e.exports=a},{}],10:[function(t,e,n){"use strict";function a(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}e.exports=a},{}],11:[function(t,e,n){"use strict";e.exports=function(t,e){var n,a,r,i,s,o,l,h,d,f,u,c,_,g,p,m,b,w,v,k,y,x,z,B,C;n=t.state,a=t.next_in,B=t.input,r=a+(t.avail_in-5),i=t.next_out,C=t.output,s=i-(e-t.avail_out),o=i+(t.avail_out-257),l=n.dmax,h=n.wsize,d=n.whave,f=n.wnext,u=n.window,c=n.hold,_=n.bits,g=n.lencode,p=n.distcode,m=(1<<n.lenbits)-1,b=(1<<n.distbits)-1;t:do{_<15&&(c+=B[a++]<<_,_+=8,c+=B[a++]<<_,_+=8),w=g[c&m];e:for(;;){if(v=w>>>24,c>>>=v,_-=v,0===(v=w>>>16&255))C[i++]=65535&w;else{if(!(16&v)){if(0==(64&v)){w=g[(65535&w)+(c&(1<<v)-1)];continue e}if(32&v){n.mode=12;break t}t.msg="invalid literal/length code",n.mode=30;break t}k=65535&w,v&=15,v&&(_<v&&(c+=B[a++]<<_,_+=8),k+=c&(1<<v)-1,c>>>=v,_-=v),_<15&&(c+=B[a++]<<_,_+=8,c+=B[a++]<<_,_+=8),w=p[c&b];n:for(;;){if(v=w>>>24,c>>>=v,_-=v,!(16&(v=w>>>16&255))){if(0==(64&v)){w=p[(65535&w)+(c&(1<<v)-1)];continue n}t.msg="invalid distance code",n.mode=30;break t}if(y=65535&w,v&=15,_<v&&(c+=B[a++]<<_,(_+=8)<v&&(c+=B[a++]<<_,_+=8)),(y+=c&(1<<v)-1)>l){t.msg="invalid distance too far back",n.mode=30;break t}if(c>>>=v,_-=v,v=i-s,y>v){if((v=y-v)>d&&n.sane){t.msg="invalid distance too far back",n.mode=30;break t}if(x=0,z=u,0===f){if(x+=h-v,v<k){k-=v;do{C[i++]=u[x++]}while(--v);x=i-y,z=C}}else if(f<v){if(x+=h+f-v,(v-=f)<k){k-=v;do{C[i++]=u[x++]}while(--v);if(x=0,f<k){v=f,k-=v;do{C[i++]=u[x++]}while(--v);x=i-y,z=C}}}else if(x+=f-v,v<k){k-=v;do{C[i++]=u[x++]}while(--v);x=i-y,z=C}for(;k>2;)C[i++]=z[x++],C[i++]=z[x++],C[i++]=z[x++],k-=3;k&&(C[i++]=z[x++],k>1&&(C[i++]=z[x++]))}else{x=i-y;do{C[i++]=C[x++],C[i++]=C[x++],C[i++]=C[x++],k-=3}while(k>2);k&&(C[i++]=C[x++],k>1&&(C[i++]=C[x++]))}break}}break}}while(a<r&&i<o);k=_>>3,a-=k,_-=k<<3,c&=(1<<_)-1,t.next_in=a,t.next_out=i,t.avail_in=a<r?r-a+5:5-(a-r),t.avail_out=i<o?o-i+257:257-(i-o),n.hold=c,n.bits=_}},{}],12:[function(t,e,n){"use strict";function a(t){return(t>>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)}function r(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new b.Buf16(320),this.work=new b.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function i(t){var e;return t&&t.state?(e=t.state,t.total_in=t.total_out=e.total=0,t.msg="",e.wrap&&(t.adler=1&e.wrap),e.mode=T,e.last=0,e.havedict=0,e.dmax=32768,e.head=null,e.hold=0,e.bits=0,e.lencode=e.lendyn=new b.Buf32(gt),e.distcode=e.distdyn=new b.Buf32(pt),e.sane=1,e.back=-1,E):N}function s(t){var e;return t&&t.state?(e=t.state,e.wsize=0,e.whave=0,e.wnext=0,i(t)):N}function o(t,e){var n,a;return t&&t.state?(a=t.state,e<0?(n=0,e=-e):(n=1+(e>>4),e<48&&(e&=15)),e&&(e<8||e>15)?N:(null!==a.window&&a.wbits!==e&&(a.window=null),a.wrap=n,a.wbits=e,s(t))):N}function l(t,e){var n,a;return t?(a=new r,t.state=a,a.window=null,n=o(t,e),n!==E&&(t.state=null),n):N}function h(t){return l(t,mt)}function d(t){if(bt){var e;for(p=new b.Buf32(512),m=new b.Buf32(32),e=0;e<144;)t.lens[e++]=8;for(;e<256;)t.lens[e++]=9;for(;e<280;)t.lens[e++]=7;for(;e<288;)t.lens[e++]=8;for(y(z,t.lens,0,288,p,0,t.work,{bits:9}),e=0;e<32;)t.lens[e++]=5;y(B,t.lens,0,32,m,0,t.work,{bits:5}),bt=!1}t.lencode=p,t.lenbits=9,t.distcode=m,t.distbits=5}function f(t,e,n,a){var r,i=t.state;return null===i.window&&(i.wsize=1<<i.wbits,i.wnext=0,i.whave=0,i.window=new b.Buf8(i.wsize)),a>=i.wsize?(b.arraySet(i.window,e,n-i.wsize,i.wsize,0),i.wnext=0,i.whave=i.wsize):(r=i.wsize-i.wnext,r>a&&(r=a),b.arraySet(i.window,e,n-a,r,i.wnext),a-=r,a?(b.arraySet(i.window,e,n-a,a,0),i.wnext=a,i.whave=i.wsize):(i.wnext+=r,i.wnext===i.wsize&&(i.wnext=0),i.whave<i.wsize&&(i.whave+=r))),0}function u(t,e){var n,r,i,s,o,l,h,u,c,_,g,p,m,gt,pt,mt,bt,wt,vt,kt,yt,xt,zt,Bt,Ct=0,At=new b.Buf8(4),St=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];if(!t||!t.state||!t.output||!t.input&&0!==t.avail_in)return N;n=t.state,n.mode===q&&(n.mode=G),o=t.next_out,i=t.output,h=t.avail_out,s=t.next_in,r=t.input,l=t.avail_in,u=n.hold,c=n.bits,_=l,g=h,xt=E;t:for(;;)switch(n.mode){case T:if(0===n.wrap){n.mode=G;break}for(;c<16;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(2&n.wrap&&35615===u){n.check=0,At[0]=255&u,At[1]=u>>>8&255,n.check=v(n.check,At,2,0),u=0,c=0,n.mode=j;break}if(n.flags=0,n.head&&(n.head.done=!1),!(1&n.wrap)||(((255&u)<<8)+(u>>8))%31){t.msg="incorrect header check",n.mode=ut;break}if((15&u)!==U){t.msg="unknown compression method",n.mode=ut;break}if(u>>>=4,c-=4,yt=8+(15&u),0===n.wbits)n.wbits=yt;else if(yt>n.wbits){t.msg="invalid window size",n.mode=ut;break}n.dmax=1<<yt,t.adler=n.check=1,n.mode=512&u?Y:q,u=0,c=0;break;case j:for(;c<16;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(n.flags=u,(255&n.flags)!==U){t.msg="unknown compression method",n.mode=ut;break}if(57344&n.flags){t.msg="unknown header flags set",n.mode=ut;break}n.head&&(n.head.text=u>>8&1),512&n.flags&&(At[0]=255&u,At[1]=u>>>8&255,n.check=v(n.check,At,2,0)),u=0,c=0,n.mode=F;case F:for(;c<32;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}n.head&&(n.head.time=u),512&n.flags&&(At[0]=255&u,At[1]=u>>>8&255,At[2]=u>>>16&255,At[3]=u>>>24&255,n.check=v(n.check,At,4,0)),u=0,c=0,n.mode=L;case L:for(;c<16;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}n.head&&(n.head.xflags=255&u,n.head.os=u>>8),512&n.flags&&(At[0]=255&u,At[1]=u>>>8&255,n.check=v(n.check,At,2,0)),u=0,c=0,n.mode=H;case H:if(1024&n.flags){for(;c<16;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}n.length=u,n.head&&(n.head.extra_len=u),512&n.flags&&(At[0]=255&u,At[1]=u>>>8&255,n.check=v(n.check,At,2,0)),u=0,c=0}else n.head&&(n.head.extra=null);n.mode=M;case M:if(1024&n.flags&&(p=n.length,p>l&&(p=l),p&&(n.head&&(yt=n.head.extra_len-n.length,n.head.extra||(n.head.extra=new Array(n.head.extra_len)),b.arraySet(n.head.extra,r,s,p,yt)),512&n.flags&&(n.check=v(n.check,r,p,s)),l-=p,s+=p,n.length-=p),n.length))break t;n.length=0,n.mode=P;case P:if(2048&n.flags){if(0===l)break t;p=0;do{yt=r[s+p++],n.head&&yt&&n.length<65536&&(n.head.name+=String.fromCharCode(yt))}while(yt&&p<l);if(512&n.flags&&(n.check=v(n.check,r,p,s)),l-=p,s+=p,yt)break t}else n.head&&(n.head.name=null);n.length=0,n.mode=W;case W:if(4096&n.flags){if(0===l)break t;p=0;do{yt=r[s+p++],n.head&&yt&&n.length<65536&&(n.head.comment+=String.fromCharCode(yt))}while(yt&&p<l);if(512&n.flags&&(n.check=v(n.check,r,p,s)),l-=p,s+=p,yt)break t}else n.head&&(n.head.comment=null);n.mode=K;case K:if(512&n.flags){for(;c<16;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(u!==(65535&n.check)){t.msg="header crc mismatch",n.mode=ut;break}u=0,c=0}n.head&&(n.head.hcrc=n.flags>>9&1,n.head.done=!0),t.adler=n.check=0,n.mode=q;break;case Y:for(;c<32;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}t.adler=n.check=a(u),u=0,c=0,n.mode=$;case $:if(0===n.havedict)return t.next_out=o,t.avail_out=h,t.next_in=s,t.avail_in=l,n.hold=u,n.bits=c,Z;t.adler=n.check=1,n.mode=q;case q:if(e===A||e===S)break t;case G:if(n.last){u>>>=7&c,c-=7&c,n.mode=ht;break}for(;c<3;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}switch(n.last=1&u,u>>>=1,c-=1,3&u){case 0:n.mode=X;break;case 1:if(d(n),n.mode=nt,e===S){u>>>=2,c-=2;break t}break;case 2:n.mode=V;break;case 3:t.msg="invalid block type",n.mode=ut}u>>>=2,c-=2;break;case X:for(u>>>=7&c,c-=7&c;c<32;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if((65535&u)!=(u>>>16^65535)){t.msg="invalid stored block lengths",n.mode=ut;break}if(n.length=65535&u,u=0,c=0,n.mode=J,e===S)break t;case J:n.mode=Q;case Q:if(p=n.length){if(p>l&&(p=l),p>h&&(p=h),0===p)break t;b.arraySet(i,r,s,p,o),l-=p,s+=p,h-=p,o+=p,n.length-=p;break}n.mode=q;break;case V:for(;c<14;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(n.nlen=257+(31&u),u>>>=5,c-=5,n.ndist=1+(31&u),u>>>=5,c-=5,n.ncode=4+(15&u),u>>>=4,c-=4,n.nlen>286||n.ndist>30){t.msg="too many length or distance symbols",n.mode=ut;break}n.have=0,n.mode=tt;case tt:for(;n.have<n.ncode;){for(;c<3;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}n.lens[St[n.have++]]=7&u,u>>>=3,c-=3}for(;n.have<19;)n.lens[St[n.have++]]=0;if(n.lencode=n.lendyn,n.lenbits=7,zt={bits:n.lenbits},xt=y(x,n.lens,0,19,n.lencode,0,n.work,zt),n.lenbits=zt.bits,xt){t.msg="invalid code lengths set",n.mode=ut;break}n.have=0,n.mode=et;case et:for(;n.have<n.nlen+n.ndist;){for(;Ct=n.lencode[u&(1<<n.lenbits)-1],pt=Ct>>>24,mt=Ct>>>16&255,bt=65535&Ct,!(pt<=c);){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(bt<16)u>>>=pt,c-=pt,n.lens[n.have++]=bt;else{if(16===bt){for(Bt=pt+2;c<Bt;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(u>>>=pt,c-=pt,0===n.have){t.msg="invalid bit length repeat",n.mode=ut;break}yt=n.lens[n.have-1],p=3+(3&u),u>>>=2,c-=2}else if(17===bt){for(Bt=pt+3;c<Bt;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}u>>>=pt,c-=pt,yt=0,p=3+(7&u),u>>>=3,c-=3}else{for(Bt=pt+7;c<Bt;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}u>>>=pt,c-=pt,yt=0,p=11+(127&u),u>>>=7,c-=7}if(n.have+p>n.nlen+n.ndist){t.msg="invalid bit length repeat",n.mode=ut;break}for(;p--;)n.lens[n.have++]=yt}}if(n.mode===ut)break;if(0===n.lens[256]){t.msg="invalid code -- missing end-of-block",n.mode=ut;break}if(n.lenbits=9,zt={bits:n.lenbits},xt=y(z,n.lens,0,n.nlen,n.lencode,0,n.work,zt),n.lenbits=zt.bits,xt){t.msg="invalid literal/lengths set",n.mode=ut;break}if(n.distbits=6,n.distcode=n.distdyn,zt={bits:n.distbits},xt=y(B,n.lens,n.nlen,n.ndist,n.distcode,0,n.work,zt),n.distbits=zt.bits,xt){t.msg="invalid distances set",n.mode=ut;break}if(n.mode=nt,e===S)break t;case nt:n.mode=at;case at:if(l>=6&&h>=258){t.next_out=o,t.avail_out=h,t.next_in=s,t.avail_in=l,n.hold=u,n.bits=c,k(t,g),o=t.next_out,i=t.output,h=t.avail_out,s=t.next_in,r=t.input,l=t.avail_in,u=n.hold,c=n.bits,n.mode===q&&(n.back=-1);break}for(n.back=0;Ct=n.lencode[u&(1<<n.lenbits)-1],pt=Ct>>>24,mt=Ct>>>16&255,bt=65535&Ct,!(pt<=c);){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(mt&&0==(240&mt)){for(wt=pt,vt=mt,kt=bt;Ct=n.lencode[kt+((u&(1<<wt+vt)-1)>>wt)],pt=Ct>>>24,mt=Ct>>>16&255,bt=65535&Ct,!(wt+pt<=c);){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}u>>>=wt,c-=wt,n.back+=wt}if(u>>>=pt,c-=pt,n.back+=pt,n.length=bt,0===mt){n.mode=lt;break}if(32&mt){n.back=-1,n.mode=q;break}if(64&mt){t.msg="invalid literal/length code",n.mode=ut;break}n.extra=15&mt,n.mode=rt;case rt:if(n.extra){for(Bt=n.extra;c<Bt;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}n.length+=u&(1<<n.extra)-1,u>>>=n.extra,c-=n.extra,n.back+=n.extra}n.was=n.length,n.mode=it;case it:for(;Ct=n.distcode[u&(1<<n.distbits)-1],pt=Ct>>>24,mt=Ct>>>16&255,bt=65535&Ct,!(pt<=c);){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(0==(240&mt)){for(wt=pt,vt=mt,kt=bt;Ct=n.distcode[kt+((u&(1<<wt+vt)-1)>>wt)],pt=Ct>>>24,mt=Ct>>>16&255,bt=65535&Ct,!(wt+pt<=c);){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}u>>>=wt,c-=wt,n.back+=wt}if(u>>>=pt,c-=pt,n.back+=pt,64&mt){t.msg="invalid distance code",n.mode=ut;break}n.offset=bt,n.extra=15&mt,n.mode=st;case st:if(n.extra){for(Bt=n.extra;c<Bt;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}n.offset+=u&(1<<n.extra)-1,u>>>=n.extra,c-=n.extra,n.back+=n.extra}if(n.offset>n.dmax){t.msg="invalid distance too far back",n.mode=ut;break}n.mode=ot;case ot:if(0===h)break t;if(p=g-h,n.offset>p){if((p=n.offset-p)>n.whave&&n.sane){t.msg="invalid distance too far back",n.mode=ut;break}p>n.wnext?(p-=n.wnext,m=n.wsize-p):m=n.wnext-p,p>n.length&&(p=n.length),gt=n.window}else gt=i,m=o-n.offset,p=n.length;p>h&&(p=h),h-=p,n.length-=p;do{i[o++]=gt[m++]}while(--p);0===n.length&&(n.mode=at);break;case lt:if(0===h)break t;i[o++]=n.length,h--,n.mode=at;break;case ht:if(n.wrap){for(;c<32;){if(0===l)break t;l--,u|=r[s++]<<c,c+=8}if(g-=h,t.total_out+=g,n.total+=g,g&&(t.adler=n.check=n.flags?v(n.check,i,g,o-g):w(n.check,i,g,o-g)),g=h,(n.flags?u:a(u))!==n.check){t.msg="incorrect data check",n.mode=ut;break}u=0,c=0}n.mode=dt;case dt:if(n.wrap&&n.flags){for(;c<32;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(u!==(4294967295&n.total)){t.msg="incorrect length check",n.mode=ut;break}u=0,c=0}n.mode=ft;case ft:xt=O;break t;case ut:xt=R;break t;case ct:return D;case _t:default:return N}return t.next_out=o,t.avail_out=h,t.next_in=s,t.avail_in=l,n.hold=u,n.bits=c,(n.wsize||g!==t.avail_out&&n.mode<ut&&(n.mode<ht||e!==C))&&f(t,t.output,t.next_out,g-t.avail_out)?(n.mode=ct,D):(_-=t.avail_in,g-=t.avail_out,t.total_in+=_,t.total_out+=g,n.total+=g,n.wrap&&g&&(t.adler=n.check=n.flags?v(n.check,i,g,t.next_out-g):w(n.check,i,g,t.next_out-g)),t.data_type=n.bits+(n.last?64:0)+(n.mode===q?128:0)+(n.mode===nt||n.mode===J?256:0),(0===_&&0===g||e===C)&&xt===E&&(xt=I),xt)}function c(t){if(!t||!t.state)return N;var e=t.state;return e.window&&(e.window=null),t.state=null,E}function _(t,e){var n;return t&&t.state?(n=t.state,0==(2&n.wrap)?N:(n.head=e,e.done=!1,E)):N}function g(t,e){var n,a,r=e.length;return t&&t.state?(n=t.state,0!==n.wrap&&n.mode!==$?N:n.mode===$&&(a=1,(a=w(a,e,r,0))!==n.check)?R:f(t,e,r,r)?(n.mode=ct,D):(n.havedict=1,E)):N}var p,m,b=t("../utils/common"),w=t("./adler32"),v=t("./crc32"),k=t("./inffast"),y=t("./inftrees"),x=0,z=1,B=2,C=4,A=5,S=6,E=0,O=1,Z=2,N=-2,R=-3,D=-4,I=-5,U=8,T=1,j=2,F=3,L=4,H=5,M=6,P=7,W=8,K=9,Y=10,$=11,q=12,G=13,X=14,J=15,Q=16,V=17,tt=18,et=19,nt=20,at=21,rt=22,it=23,st=24,ot=25,lt=26,ht=27,dt=28,ft=29,ut=30,ct=31,_t=32,gt=852,pt=592,mt=15,bt=!0;n.inflateReset=s,n.inflateReset2=o,n.inflateResetKeep=i,n.inflateInit=h,n.inflateInit2=l,n.inflate=u,n.inflateEnd=c,n.inflateGetHeader=_,n.inflateSetDictionary=g,n.inflateInfo="pako inflate (from Nodeca project)"},{"../utils/common":5,"./adler32":7,"./crc32":9,"./inffast":11,"./inftrees":13}],13:[function(t,e,n){"use strict";var a=t("../utils/common"),r=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],i=[16,16,16,16,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,16,72,78],s=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0],o=[16,16,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,64,64];e.exports=function(t,e,n,l,h,d,f,u){var c,_,g,p,m,b,w,v,k,y=u.bits,x=0,z=0,B=0,C=0,A=0,S=0,E=0,O=0,Z=0,N=0,R=null,D=0,I=new a.Buf16(16),U=new a.Buf16(16),T=null,j=0;for(x=0;x<=15;x++)I[x]=0;for(z=0;z<l;z++)I[e[n+z]]++;for(A=y,C=15;C>=1&&0===I[C];C--);if(A>C&&(A=C),0===C)return h[d++]=20971520,h[d++]=20971520,u.bits=1,0;for(B=1;B<C&&0===I[B];B++);for(A<B&&(A=B),O=1,x=1;x<=15;x++)if(O<<=1,(O-=I[x])<0)return-1;if(O>0&&(0===t||1!==C))return-1;for(U[1]=0,x=1;x<15;x++)U[x+1]=U[x]+I[x];for(z=0;z<l;z++)0!==e[n+z]&&(f[U[e[n+z]]++]=z);if(0===t?(R=T=f,b=19):1===t?(R=r,D-=257,T=i,j-=257,b=256):(R=s,T=o,b=-1),N=0,z=0,x=B,m=d,S=A,E=0,g=-1,Z=1<<A,p=Z-1,1===t&&Z>852||2===t&&Z>592)return 1;for(;;){w=x-E,f[z]<b?(v=0,k=f[z]):f[z]>b?(v=T[j+f[z]],k=R[D+f[z]]):(v=96,k=0),c=1<<x-E,_=1<<S,B=_;do{_-=c,h[m+(N>>E)+_]=w<<24|v<<16|k|0}while(0!==_);for(c=1<<x-1;N&c;)c>>=1;if(0!==c?(N&=c-1,N+=c):N=0,z++,0==--I[x]){if(x===C)break;x=e[n+f[z]]}if(x>A&&(N&p)!==g){for(0===E&&(E=A),m+=B,S=x-E,O=1<<S;S+E<C&&!((O-=I[S+E])<=0);)S++,O<<=1;if(Z+=1<<S,1===t&&Z>852||2===t&&Z>592)return 1;g=N&p,h[g]=A<<24|S<<16|m-d|0}}return 0!==N&&(h[m+N]=x-E<<24|64<<16|0),u.bits=A,0}},{"../utils/common":5}],14:[function(t,e,n){"use strict";e.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],15:[function(t,e,n){"use strict";function a(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}e.exports=a},{}]},{},[3])(3)})}]); | |
| 0 | 2 | \ No newline at end of file | ... | ... |
doc/lib/js/docsify@4.js
0 → 100644
| 1 | +!function(){function c(i){var o=Object.create(null);return function(e){var n=f(e)?e:JSON.stringify(e);return o[n]||(o[n]=i(e))}}var a=c(function(e){return e.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}),u=Object.prototype.hasOwnProperty,m=Object.assign||function(e){for(var n=arguments,i=1;i<arguments.length;i++){var o,t=Object(n[i]);for(o in t)u.call(t,o)&&(e[o]=t[o])}return e};function f(e){return"string"==typeof e||"number"==typeof e}function d(){}function o(e){return"function"==typeof e}function g(e){e=e.match(/^([^:/?#]+:)?(?:\/{2,}([^/?#]*))?([^?#]+)?(\?[^#]*)?(#.*)?/);return"string"==typeof e[1]&&0<e[1].length&&e[1].toLowerCase()!==location.protocol||"string"==typeof e[2]&&0<e[2].length&&e[2].replace(new RegExp(":("+{"http:":80,"https:":443}[location.protocol]+")?$"),"")!==location.host}var s=document.body.clientWidth<=600,t=window.history&&window.history.pushState&&window.history.replaceState&&!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/),i={};function l(e,n){if(void 0===n&&(n=!1),"string"==typeof e){if(void 0!==window.Vue)return b(e);e=n?b(e):i[e]||(i[e]=b(e))}return e}var v=document,h=v.body,_=v.head;function b(e,n){return n?e.querySelector(n):v.querySelector(e)}function k(e,n){return[].slice.call(n?e.querySelectorAll(n):v.querySelectorAll(e))}function w(e,n){return e=v.createElement(e),n&&(e.innerHTML=n),e}function r(e,n){return e.appendChild(n)}function y(e,n){return e.insertBefore(n,e.children[0])}function p(e,n,i){o(n)?window.addEventListener(e,n):e.addEventListener(n,i)}function x(e,n,i){o(n)?window.removeEventListener(e,n):e.removeEventListener(n,i)}function S(e,n,i){e&&e.classList[i?n:"toggle"](i||n)}function e(e,n){var i=(n=void 0===n?document:n).readyState;if("complete"===i||"interactive"===i)return setTimeout(e,0);n.addEventListener("DOMContentLoaded",e)}var n=Object.freeze({__proto__:null,getNode:l,$:v,body:h,head:_,find:b,findAll:k,create:w,appendTo:r,before:y,on:p,off:x,toggleClass:S,style:function(e){r(_,w("style",e))},documentReady:e});function A(e,n){return-1!==e.indexOf(n,e.length-n.length)}var $=decodeURIComponent,z=encodeURIComponent;function F(e){var n={};return(e=e.trim().replace(/^(\?|#|&)/,""))&&e.split("&").forEach(function(e){e=e.replace(/\+/g," ").split("=");n[e[0]]=e[1]&&$(e[1])}),n}function E(e,n){void 0===n&&(n=[]);var i,o=[];for(i in e)-1<n.indexOf(i)||o.push(e[i]?(z(i)+"="+z(e[i])).toLowerCase():z(i));return o.length?"?"+o.join("&"):""}var T=c(function(e){return/(:|(\/{2}))/g.test(e)}),C=c(function(e){return e.split(/[?#]/)[0]}),R=c(function(e){if(/\/$/g.test(e))return e;e=e.match(/(\S*\/)[^/]+$/);return e?e[1]:""}),j=c(function(e){return e.replace(/^\/+/,"/").replace(/([^:])\/{2,}/g,"$1/")}),O=c(function(e){for(var n=e.replace(/^\//,"").split("/"),i=[],o=0,t=n.length;o<t;o++){var a=n[o];".."===a?i.pop():"."!==a&&i.push(a)}return"/"+i.join("/")});function L(e){return e.split("/").filter(function(e){return-1===e.indexOf("#")}).join("/")}function q(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];return j(e.map(L).join("/"))}var P=c(function(e){return e.replace("#","?id=")}),M={};function I(e){this.config=e}function N(e){var n=location.href.indexOf("#");location.replace(location.href.slice(0,0<=n?n:0)+"#"+e)}I.prototype.getBasePath=function(){return this.config.basePath},I.prototype.getFile=function(e,n){void 0===e&&(e=this.getCurrentPath());var i,o,t=this.config,a=this.getBasePath(),r="string"==typeof t.ext?t.ext:".md";return e=t.alias?function e(n,i,o){var t=Object.keys(i).filter(function(e){return(M[e]||(M[e]=new RegExp("^"+e+"$"))).test(n)&&n!==o})[0];return t?e(n.replace(M[t],i[t]),i,n):n}(e,t.alias):e,i=e,o=r,e=(e=new RegExp("\\.("+o.replace(/^\./,"")+"|html)$","g").test(i)?i:/\/$/g.test(i)?i+"README"+o:""+i+o)==="/README"+r&&t.homepage||e,e=T(e)?e:q(a,e),e=n?e.replace(new RegExp("^"+a),""):e},I.prototype.onchange=function(e){(e=void 0===e?d:e)()},I.prototype.getCurrentPath=function(){},I.prototype.normalize=function(){},I.prototype.parse=function(){},I.prototype.toURL=function(e,n,i){var o=i&&"#"===e[0],t=this.parse(P(e));if(t.query=m({},t.query,n),e=(e=t.path+E(t.query)).replace(/\.md(\?)|\.md$/,"$1"),o&&(e=(0<(o=i.indexOf("?"))?i.substring(0,o):i)+e),this.config.relativePath&&0!==e.indexOf("/")){i=i.substring(0,i.lastIndexOf("/")+1);return j(O(i+e))}return j("/"+e)};var H=function(o){function e(e){o.call(this,e),this.mode="hash"}return o&&(e.__proto__=o),((e.prototype=Object.create(o&&o.prototype)).constructor=e).prototype.getBasePath=function(){var e=window.location.pathname||"",n=this.config.basePath,e=A(e,".html")?e+"#/"+n:e+"/"+n;return/^(\/|https?:)/g.test(n)?n:j(e)},e.prototype.getCurrentPath=function(){var e=location.href,n=e.indexOf("#");return-1===n?"":e.slice(n+1)},e.prototype.onchange=function(i){void 0===i&&(i=d);var o=!1;p("click",function(e){e="A"===e.target.tagName?e.target:e.target.parentNode;e&&"A"===e.tagName&&!/_blank/.test(e.target)&&(o=!0)}),p("hashchange",function(e){var n=o?"navigate":"history";o=!1,i({event:e,source:n})})},e.prototype.normalize=function(){var e=this.getCurrentPath();if("/"===(e=P(e)).charAt(0))return N(e);N("/"+e)},e.prototype.parse=function(e){var n="",i=(e=void 0===e?location.href:e).indexOf("#"),i=(e=0<=i?e.slice(i+1):e).indexOf("?");return 0<=i&&(n=e.slice(i+1),e=e.slice(0,i)),{path:e,file:this.getFile(e,!0),query:F(n)}},e.prototype.toURL=function(e,n,i){return"#"+o.prototype.toURL.call(this,e,n,i)},e}(I),D=function(n){function e(e){n.call(this,e),this.mode="history"}return n&&(e.__proto__=n),((e.prototype=Object.create(n&&n.prototype)).constructor=e).prototype.getCurrentPath=function(){var e=this.getBasePath(),n=window.location.pathname;return((n=e&&0===n.indexOf(e)?n.slice(e.length):n)||"/")+window.location.search+window.location.hash},e.prototype.onchange=function(i){var o=this;void 0===i&&(i=d),p("click",function(e){var n="A"===e.target.tagName?e.target:e.target.parentNode;n&&"A"===n.tagName&&!/_blank/.test(n.target)&&(e.preventDefault(),n=n.href,-1!==o.config.crossOriginLinks.indexOf(n)?window.open(n,"_self"):window.history.pushState({key:n},"",n),i({event:e,source:"navigate"}))}),p("popstate",function(e){i({event:e,source:"history"})})},e.prototype.parse=function(e){var n="",i=(e=void 0===e?location.href:e).indexOf("?");0<=i&&(n=e.slice(i+1),e=e.slice(0,i));var o=q(location.origin),i=e.indexOf(o);return{path:e=-1<i?e.slice(i+o.length):e,file:this.getFile(e),query:F(n)}},e}(I),U={};var Z,B,V=/([^{]*?)\w(?=\})/g,Y={YYYY:"getFullYear",YY:"getYear",MM:function(e){return e.getMonth()+1},DD:"getDate",HH:"getHours",mm:"getMinutes",ss:"getSeconds",fff:"getMilliseconds"};function G(e){var n,i=e.loaded,o=e.total,t=e.step;Z||((e=w("div")).classList.add("progress"),r(h,e),Z=e),n=t?80<(n=parseInt(Z.style.width||0,10)+t)?80:n:Math.floor(i/o*100),Z.style.opacity=1,Z.style.width=95<=n?"100%":n+"%",95<=n&&(clearTimeout(B),B=setTimeout(function(e){Z.style.opacity=0,Z.style.width="0%"},200))}var W={};function X(t,e,n){void 0===e&&(e=!1),void 0===n&&(n={});function a(){r.addEventListener.apply(r,arguments)}var i,r=new XMLHttpRequest,o=W[t];if(o)return{then:function(e){return e(o.content,o.opt)},abort:d};for(i in r.open("GET",t),n)u.call(n,i)&&r.setRequestHeader(i,n[i]);return r.send(),{then:function(n,i){var o;void 0===i&&(i=d),e&&(o=setInterval(function(e){return G({step:Math.floor(5*Math.random()+1)})},500),a("progress",G),a("loadend",function(e){G(e),clearInterval(o)})),a("error",i),a("load",function(e){var e=e.target;400<=e.status?i(e):(e=W[t]={content:e.response,opt:{updatedAt:r.getResponseHeader("last-modified")}},n(e.content,e.opt))})},abort:function(e){return 4!==r.readyState&&r.abort()}}}function Q(e,n){e.innerHTML=e.innerHTML.replace(/var\(\s*--theme-color.*?\)/g,n)}var J=v.title;function K(){var e,n=l("section.cover");n&&(e=n.getBoundingClientRect().height,window.pageYOffset>=e||n.classList.contains("hidden")?S(h,"add","sticky"):S(h,"remove","sticky"))}function ee(e,n,o,i){var t=[];null!=(n=l(n))&&(t=k(n,"a"));var a,r=decodeURI(e.toURL(e.getCurrentPath()));return t.sort(function(e,n){return n.href.length-e.href.length}).forEach(function(e){var n=decodeURI(e.getAttribute("href")),i=o?e.parentNode:e;e.title=e.title||e.innerText,0!==r.indexOf(n)||a?S(i,"remove","active"):(a=e,S(i,"add","active"))}),i&&(v.title=a?a.title||a.innerText+" - "+J:J),a}function ne(e,n){for(var i=0;i<n.length;i++){var o=n[i];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}var ie=(function(e,n,i){return n&&ne(e.prototype,n),i&&ne(e,i),e}(oe,[{key:"getIntermediateValue",value:function(e){return this.decimal?e:Math.round(e)}},{key:"getFinalValue",value:function(){return this.end}}]),oe);function oe(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,oe),this.start=e.start,this.end=e.end,this.decimal=e.decimal}function te(e,n){for(var i=0;i<n.length;i++){var o=n[i];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}var ae=(function(e,n,i){return n&&te(e.prototype,n),i&&te(e,i),e}(re,[{key:"begin",value:function(){return this.isRunning||this.next===this.end||(this.frame=window.requestAnimationFrame(this._tick.bind(this))),this}},{key:"stop",value:function(){return window.cancelAnimationFrame(this.frame),this.isRunning=!1,this.frame=null,this.timeStart=null,this.next=null,this}},{key:"on",value:function(e,n){return this.events[e]=this.events[e]||[],this.events[e].push(n),this}},{key:"_emit",value:function(e,n){var i=this,e=this.events[e];e&&e.forEach(function(e){return e.call(i,n)})}},{key:"_tick",value:function(e){this.isRunning=!0;var n=this.next||this.start;this.timeStart||(this.timeStart=e),this.timeElapsed=e-this.timeStart,this.next=this.ease(this.timeElapsed,this.start,this.end-this.start,this.duration),this._shouldTick(n)?(this._emit("tick",this.tweener.getIntermediateValue(this.next)),this.frame=window.requestAnimationFrame(this._tick.bind(this))):(this._emit("tick",this.tweener.getFinalValue()),this._emit("done",null))}},{key:"_shouldTick",value:function(e){return{up:this.next<this.end&&e<=this.next,down:this.next>this.end&&e>=this.next}[this.direction]}},{key:"_defaultEase",value:function(e,n,i,o){return(e/=o/2)<1?i/2*e*e+n:-i/2*(--e*(e-2)-1)+n}}]),re);function re(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,re),this.duration=e.duration||1e3,this.ease=e.easing||this._defaultEase,this.tweener=e.tweener||new ie(e),this.start=this.tweener.start,this.end=this.tweener.end,this.frame=null,this.next=null,this.isRunning=!1,this.events={},this.direction=this.start<this.end?"up":"down"}var ce=document.currentScript;function ue(e){var n,i=m({auto2top:!1,autoHeader:!1,basePath:"",catchPluginErrors:!0,cornerExternalLinkTarget:"_blank",coverpage:"",crossOriginLinks:[],el:"#app",executeScript:null,ext:".md",externalLinkRel:"noopener",externalLinkTarget:"_blank",formatUpdated:"",ga:"",homepage:"README.md",loadNavbar:null,loadSidebar:null,maxLevel:6,mergeNavbar:!1,name:"",nameLink:window.location.pathname,nativeEmoji:!1,noCompileLinks:[],noEmoji:!1,notFoundPage:!0,relativePath:!1,repo:"",routes:{},routerMode:"hash",subMaxLevel:0,themeColor:"",topMargin:0},"function"==typeof window.$docsify?window.$docsify(e):window.$docsify),o=ce||[].slice.call(document.getElementsByTagName("script")).filter(function(e){return/docsify\./.test(e.src)})[0];if(o)for(var t in i)!u.call(i,t)||f(n=o.getAttribute("data-"+a(t)))&&(i[t]=""===n||n);return!0===i.loadSidebar&&(i.loadSidebar="_sidebar"+i.ext),!0===i.loadNavbar&&(i.loadNavbar="_navbar"+i.ext),!0===i.coverpage&&(i.coverpage="_coverpage"+i.ext),!0===i.repo&&(i.repo=""),!0===i.name&&(i.name=""),window.$docsify=i}var fe={},pe=!1,de=null,ge=!0,se=0;function le(e){if(ge){for(var n,i=l(".sidebar"),o=k(".anchor"),t=b(i,".sidebar-nav"),a=b(i,"li.active"),r=document.documentElement,c=(r&&r.scrollTop||document.body.scrollTop)-se,u=0,f=o.length;u<f;u+=1){var p=o[u];if(p.offsetTop>c){n=n||p;break}n=p}!n||(r=fe[ve(e,n.getAttribute("data-id"))])&&r!==a&&(a&&a.classList.remove("active"),r.classList.add("active"),a=r,!pe&&h.classList.contains("sticky")&&(e=i.clientHeight,r=a.offsetTop+a.clientHeight+40,a=a.offsetTop>=t.scrollTop&&r<=t.scrollTop+e,i.scrollTop=a?t.scrollTop:+r<e?0:r-e))}}function ve(e,n){return decodeURIComponent(e)+"?id="+decodeURIComponent(n)}function he(e,n){var i,o;n&&(o=ue().topMargin,(i=b("#"+n))&&(i=i,void 0===(o=o)&&(o=0),de&&de.stop(),ge=!1,de=new ae({start:window.pageYOffset,end:Math.round(i.getBoundingClientRect().top)+window.pageYOffset-o,duration:500}).on("tick",function(e){return window.scrollTo(0,e)}).on("done",function(){ge=!0,de=null}).begin()),e=fe[ve(e,n)],(n=b(l(".sidebar"),"li.active"))&&n.classList.remove("active"),e&&e.classList.add("active"))}var _e=v.scrollingElement||v.documentElement;var me="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function be(e,n){return e(n={exports:{}},n.exports),n.exports}function ke(e){return $e[e]}var we=be(function(n){function e(){return{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1}}n.exports={defaults:e(),getDefaults:e,changeDefaults:function(e){n.exports.defaults=e}}}),ye=(we.defaults,we.getDefaults,we.changeDefaults,/[&<>"']/),xe=/[&<>"']/g,Se=/[<>"']|&(?!#?\w+;)/,Ae=/[<>"']|&(?!#?\w+;)/g,$e={"&":"&","<":"<",">":">",'"':""","'":"'"};var ze=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function Fe(e){return e.replace(ze,function(e,n){return"colon"===(n=n.toLowerCase())?":":"#"===n.charAt(0)?"x"===n.charAt(1)?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1)):""})}var Ee=/(^|[^\[])\^/g;var Te=/[^\w:]/g,Ce=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var Re={},je=/^[^:]+:\/*[^/]*$/,Oe=/^([^:]+:)[\s\S]*$/,Le=/^([^:]+:\/*[^/]*)[\s\S]*$/;function qe(e,n){Re[" "+e]||(je.test(e)?Re[" "+e]=e+"/":Re[" "+e]=Pe(e,"/",!0));var i=-1===(e=Re[" "+e]).indexOf(":");return"//"===n.substring(0,2)?i?n:e.replace(Oe,"$1")+n:"/"===n.charAt(0)?i?n:e.replace(Le,"$1")+n:e+n}function Pe(e,n,i){var o=e.length;if(0===o)return"";for(var t=0;t<o;){var a=e.charAt(o-t-1);if(a!==n||i){if(a===n||!i)break;t++}else t++}return e.substr(0,o-t)}var Me=function(e,n){if(n){if(ye.test(e))return e.replace(xe,ke)}else if(Se.test(e))return e.replace(Ae,ke);return e},Ie=Fe,Ne=function(i,e){i=i.source||i,e=e||"";var o={replace:function(e,n){return n=(n=n.source||n).replace(Ee,"$1"),i=i.replace(e,n),o},getRegex:function(){return new RegExp(i,e)}};return o},He=function(e,n,i){if(e){var o;try{o=decodeURIComponent(Fe(i)).replace(Te,"").toLowerCase()}catch(e){return null}if(0===o.indexOf("javascript:")||0===o.indexOf("vbscript:")||0===o.indexOf("data:"))return null}n&&!Ce.test(i)&&(i=qe(n,i));try{i=encodeURI(i).replace(/%25/g,"%")}catch(e){return null}return i},De={exec:function(){}},Ue=function(e){for(var n,i,o=arguments,t=1;t<arguments.length;t++)for(i in n=o[t])Object.prototype.hasOwnProperty.call(n,i)&&(e[i]=n[i]);return e},Ze=function(e,n){var i=e.replace(/\|/g,function(e,n,i){for(var o=!1,t=n;0<=--t&&"\\"===i[t];)o=!o;return o?"|":" |"}).split(/ \|/),o=0;if(i.length>n)i.splice(n);else for(;i.length<n;)i.push("");for(;o<i.length;o++)i[o]=i[o].trim().replace(/\\\|/g,"|");return i},Be=Pe,Ve=function(e,n){if(-1===e.indexOf(n[1]))return-1;for(var i=e.length,o=0,t=0;t<i;t++)if("\\"===e[t])t++;else if(e[t]===n[0])o++;else if(e[t]===n[1]&&--o<0)return t;return-1},Ye=function(e){e&&e.sanitize&&!e.silent&&console.warn("marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options")},Ge=function(e,n){if(n<1)return"";for(var i="";1<n;)1&n&&(i+=e),n>>=1,e+=e;return i+e},We=we.defaults,Xe=Be,Qe=Ze,Je=Me,Ke=Ve;function en(e,n,i){var o=n.href,t=n.title?Je(n.title):null,n=e[1].replace(/\\([\[\]])/g,"$1");return"!"!==e[0].charAt(0)?{type:"link",raw:i,href:o,title:t,text:n}:{type:"image",raw:i,href:o,title:t,text:Je(n)}}var nn=function(){function e(e){this.options=e||We}return e.prototype.space=function(e){e=this.rules.block.newline.exec(e);if(e)return 1<e[0].length?{type:"space",raw:e[0]}:{raw:"\n"}},e.prototype.code=function(e,n){e=this.rules.block.code.exec(e);if(e){n=n[n.length-1];if(n&&"paragraph"===n.type)return{raw:e[0],text:e[0].trimRight()};n=e[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:e[0],codeBlockStyle:"indented",text:this.options.pedantic?n:Xe(n,"\n")}}},e.prototype.fences=function(e){var n=this.rules.block.fences.exec(e);if(n){var i=n[0],e=function(e,n){if(null===(e=e.match(/^(\s+)(?:```)/)))return n;var i=e[1];return n.split("\n").map(function(e){var n=e.match(/^\s+/);return null!==n&&n[0].length>=i.length?e.slice(i.length):e}).join("\n")}(i,n[3]||"");return{type:"code",raw:i,lang:n[2]&&n[2].trim(),text:e}}},e.prototype.heading=function(e){var n=this.rules.block.heading.exec(e);if(n){var i=n[2].trim();return/#$/.test(i)&&(e=Xe(i,"#"),!this.options.pedantic&&e&&!/ $/.test(e)||(i=e.trim())),{type:"heading",raw:n[0],depth:n[1].length,text:i}}},e.prototype.nptable=function(e){e=this.rules.block.nptable.exec(e);if(e){var n={type:"table",header:Qe(e[1].replace(/^ *| *\| *$/g,"")),align:e[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:e[3]?e[3].replace(/\n$/,"").split("\n"):[],raw:e[0]};if(n.header.length===n.align.length){for(var i=n.align.length,o=0;o<i;o++)/^ *-+: *$/.test(n.align[o])?n.align[o]="right":/^ *:-+: *$/.test(n.align[o])?n.align[o]="center":/^ *:-+ *$/.test(n.align[o])?n.align[o]="left":n.align[o]=null;for(i=n.cells.length,o=0;o<i;o++)n.cells[o]=Qe(n.cells[o],n.header.length);return n}}},e.prototype.hr=function(e){e=this.rules.block.hr.exec(e);if(e)return{type:"hr",raw:e[0]}},e.prototype.blockquote=function(e){var n=this.rules.block.blockquote.exec(e);if(n){e=n[0].replace(/^ *> ?/gm,"");return{type:"blockquote",raw:n[0],text:e}}},e.prototype.list=function(e){e=this.rules.block.list.exec(e);if(e){for(var n,i,o,t,a,r=e[0],c=e[2],u=1<c.length,f={type:"list",raw:r,ordered:u,start:u?+c.slice(0,-1):"",loose:!1,items:[]},p=e[0].match(this.rules.block.item),d=!1,g=p.length,s=this.rules.block.listItemStart.exec(p[0]),l=0;l<g;l++){if(r=n=p[l],l!==g-1){if(o=this.rules.block.listItemStart.exec(p[l+1]),this.options.pedantic?o[1].length>s[1].length:o[1].length>s[0].length||3<o[1].length){p.splice(l,2,p[l]+"\n"+p[l+1]),l--,g--;continue}(!this.options.pedantic||this.options.smartLists?o[2][o[2].length-1]!==c[c.length-1]:u==(1===o[2].length))&&(i=p.slice(l+1).join("\n"),f.raw=f.raw.substring(0,f.raw.length-i.length),l=g-1),s=o}o=n.length,~(n=n.replace(/^ *([*+-]|\d+[.)]) ?/,"")).indexOf("\n ")&&(o-=n.length,n=this.options.pedantic?n.replace(/^ {1,4}/gm,""):n.replace(new RegExp("^ {1,"+o+"}","gm"),"")),o=d||/\n\n(?!\s*$)/.test(n),l!==g-1&&(d="\n"===n.charAt(n.length-1),o=o||d),o&&(f.loose=!0),this.options.gfm&&(a=void 0,(t=/^\[[ xX]\] /.test(n))&&(a=" "!==n[1],n=n.replace(/^\[[ xX]\] +/,""))),f.items.push({type:"list_item",raw:r,task:t,checked:a,loose:o,text:n})}return f}},e.prototype.html=function(e){e=this.rules.block.html.exec(e);if(e)return{type:this.options.sanitize?"paragraph":"html",raw:e[0],pre:!this.options.sanitizer&&("pre"===e[1]||"script"===e[1]||"style"===e[1]),text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(e[0]):Je(e[0]):e[0]}},e.prototype.def=function(e){e=this.rules.block.def.exec(e);if(e)return e[3]&&(e[3]=e[3].substring(1,e[3].length-1)),{tag:e[1].toLowerCase().replace(/\s+/g," "),raw:e[0],href:e[2],title:e[3]}},e.prototype.table=function(e){e=this.rules.block.table.exec(e);if(e){var n={type:"table",header:Qe(e[1].replace(/^ *| *\| *$/g,"")),align:e[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:e[3]?e[3].replace(/\n$/,"").split("\n"):[]};if(n.header.length===n.align.length){n.raw=e[0];for(var i=n.align.length,o=0;o<i;o++)/^ *-+: *$/.test(n.align[o])?n.align[o]="right":/^ *:-+: *$/.test(n.align[o])?n.align[o]="center":/^ *:-+ *$/.test(n.align[o])?n.align[o]="left":n.align[o]=null;for(i=n.cells.length,o=0;o<i;o++)n.cells[o]=Qe(n.cells[o].replace(/^ *\| *| *\| *$/g,""),n.header.length);return n}}},e.prototype.lheading=function(e){e=this.rules.block.lheading.exec(e);if(e)return{type:"heading",raw:e[0],depth:"="===e[2].charAt(0)?1:2,text:e[1]}},e.prototype.paragraph=function(e){e=this.rules.block.paragraph.exec(e);if(e)return{type:"paragraph",raw:e[0],text:"\n"===e[1].charAt(e[1].length-1)?e[1].slice(0,-1):e[1]}},e.prototype.text=function(e,n){e=this.rules.block.text.exec(e);if(e){n=n[n.length-1];return n&&"text"===n.type?{raw:e[0],text:e[0]}:{type:"text",raw:e[0],text:e[0]}}},e.prototype.escape=function(e){e=this.rules.inline.escape.exec(e);if(e)return{type:"escape",raw:e[0],text:Je(e[1])}},e.prototype.tag=function(e,n,i){e=this.rules.inline.tag.exec(e);if(e)return!n&&/^<a /i.test(e[0])?n=!0:n&&/^<\/a>/i.test(e[0])&&(n=!1),!i&&/^<(pre|code|kbd|script)(\s|>)/i.test(e[0])?i=!0:i&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(e[0])&&(i=!1),{type:this.options.sanitize?"text":"html",raw:e[0],inLink:n,inRawBlock:i,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(e[0]):Je(e[0]):e[0]}},e.prototype.link=function(e){var n=this.rules.inline.link.exec(e);if(n){e=n[2].trim();if(!this.options.pedantic&&/^</.test(e)){if(!/>$/.test(e))return;var i=Xe(e.slice(0,-1),"\\");if((e.length-i.length)%2==0)return}else{var o=Ke(n[2],"()");-1<o&&(t=(0===n[0].indexOf("!")?5:4)+n[1].length+o,n[2]=n[2].substring(0,o),n[0]=n[0].substring(0,t).trim(),n[3]="")}var t,i=n[2],o="";return this.options.pedantic?(t=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(i))&&(i=t[1],o=t[3]):o=n[3]?n[3].slice(1,-1):"",i=i.trim(),en(n,{href:(i=/^</.test(i)?this.options.pedantic&&!/>$/.test(e)?i.slice(1):i.slice(1,-1):i)&&i.replace(this.rules.inline._escapes,"$1"),title:o&&o.replace(this.rules.inline._escapes,"$1")},n[0])}},e.prototype.reflink=function(e,n){if((i=this.rules.inline.reflink.exec(e))||(i=this.rules.inline.nolink.exec(e))){var e=(i[2]||i[1]).replace(/\s+/g," ");if((e=n[e.toLowerCase()])&&e.href)return en(i,e,i[0]);var i=i[0].charAt(0);return{type:"text",raw:i,text:i}}},e.prototype.strong=function(e,n,i){void 0===i&&(i="");var o=this.rules.inline.strong.start.exec(e);if(o&&(!o[1]||o[1]&&(""===i||this.rules.inline.punctuation.exec(i)))){n=n.slice(-1*e.length);var t,a="**"===o[0]?this.rules.inline.strong.endAst:this.rules.inline.strong.endUnd;for(a.lastIndex=0;null!=(o=a.exec(n));)if(t=this.rules.inline.strong.middle.exec(n.slice(0,o.index+3)))return{type:"strong",raw:e.slice(0,t[0].length),text:e.slice(2,t[0].length-2)}}},e.prototype.em=function(e,n,i){void 0===i&&(i="");var o=this.rules.inline.em.start.exec(e);if(o&&(!o[1]||o[1]&&(""===i||this.rules.inline.punctuation.exec(i)))){n=n.slice(-1*e.length);var t,a="*"===o[0]?this.rules.inline.em.endAst:this.rules.inline.em.endUnd;for(a.lastIndex=0;null!=(o=a.exec(n));)if(t=this.rules.inline.em.middle.exec(n.slice(0,o.index+2)))return{type:"em",raw:e.slice(0,t[0].length),text:e.slice(1,t[0].length-1)}}},e.prototype.codespan=function(e){var n=this.rules.inline.code.exec(e);if(n){var i=n[2].replace(/\n/g," "),o=/[^ ]/.test(i),e=/^ /.test(i)&&/ $/.test(i);return o&&e&&(i=i.substring(1,i.length-1)),i=Je(i,!0),{type:"codespan",raw:n[0],text:i}}},e.prototype.br=function(e){e=this.rules.inline.br.exec(e);if(e)return{type:"br",raw:e[0]}},e.prototype.del=function(e){e=this.rules.inline.del.exec(e);if(e)return{type:"del",raw:e[0],text:e[2]}},e.prototype.autolink=function(e,n){e=this.rules.inline.autolink.exec(e);if(e){var i,n="@"===e[2]?"mailto:"+(i=Je(this.options.mangle?n(e[1]):e[1])):i=Je(e[1]);return{type:"link",raw:e[0],text:i,href:n,tokens:[{type:"text",raw:i,text:i}]}}},e.prototype.url=function(e,n){var i,o,t,a;if(i=this.rules.inline.url.exec(e)){if("@"===i[2])t="mailto:"+(o=Je(this.options.mangle?n(i[0]):i[0]));else{for(;a=i[0],i[0]=this.rules.inline._backpedal.exec(i[0])[0],a!==i[0];);o=Je(i[0]),t="www."===i[1]?"http://"+o:o}return{type:"link",raw:i[0],text:o,href:t,tokens:[{type:"text",raw:o,text:o}]}}},e.prototype.inlineText=function(e,n,i){e=this.rules.inline.text.exec(e);if(e){i=n?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(e[0]):Je(e[0]):e[0]:Je(this.options.smartypants?i(e[0]):e[0]);return{type:"text",raw:e[0],text:i}}},e}(),Ze=De,Ve=Ne,De=Ue,Ne={newline:/^(?: *(?:\n|$))+/,code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,fences:/^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?! {0,3}bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:Ze,table:Ze,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};Ne.def=Ve(Ne.def).replace("label",Ne._label).replace("title",Ne._title).getRegex(),Ne.bullet=/(?:[*+-]|\d{1,9}[.)])/,Ne.item=/^( *)(bull) ?[^\n]*(?:\n(?! *bull ?)[^\n]*)*/,Ne.item=Ve(Ne.item,"gm").replace(/bull/g,Ne.bullet).getRegex(),Ne.listItemStart=Ve(/^( *)(bull)/).replace("bull",Ne.bullet).getRegex(),Ne.list=Ve(Ne.list).replace(/bull/g,Ne.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+Ne.def.source+")").getRegex(),Ne._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",Ne._comment=/<!--(?!-?>)[\s\S]*?(?:-->|$)/,Ne.html=Ve(Ne.html,"i").replace("comment",Ne._comment).replace("tag",Ne._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),Ne.paragraph=Ve(Ne._paragraph).replace("hr",Ne.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",Ne._tag).getRegex(),Ne.blockquote=Ve(Ne.blockquote).replace("paragraph",Ne.paragraph).getRegex(),Ne.normal=De({},Ne),Ne.gfm=De({},Ne.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n {0,3}([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n {0,3}\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),Ne.gfm.nptable=Ve(Ne.gfm.nptable).replace("hr",Ne.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",Ne._tag).getRegex(),Ne.gfm.table=Ve(Ne.gfm.table).replace("hr",Ne.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",Ne._tag).getRegex(),Ne.pedantic=De({},Ne.normal,{html:Ve("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:\"[^\"]*\"|'[^']*'|\\s[^'\"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",Ne._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:Ze,paragraph:Ve(Ne.normal._paragraph).replace("hr",Ne.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",Ne.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});Ze={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:Ze,tag:"^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,reflinkSearch:"reflink|nolink(?!\\()",strong:{start:/^(?:(\*\*(?=[*punctuation]))|\*\*)(?![\s])|__/,middle:/^\*\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*\*$|^__(?![\s])((?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?)__$/,endAst:/[^punctuation\s]\*\*(?!\*)|[punctuation]\*\*(?!\*)(?:(?=[punctuation_\s]|$))/,endUnd:/[^\s]__(?!_)(?:(?=[punctuation*\s])|$)/},em:{start:/^(?:(\*(?=[punctuation]))|\*)(?![*\s])|_/,middle:/^\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*$|^_(?![_\s])(?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?_$/,endAst:/[^punctuation\s]\*(?!\*)|[punctuation]\*(?!\*)(?:(?=[punctuation_\s]|$))/,endUnd:/[^\s]_(?!_)(?:(?=[punctuation*\s])|$)/},code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:Ze,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n)))/,punctuation:/^([\s*punctuation])/,_punctuation:"!\"#$%&'()+\\-.,/:;<=>?@\\[\\]`^{|}~"};Ze.punctuation=Ve(Ze.punctuation).replace(/punctuation/g,Ze._punctuation).getRegex(),Ze._blockSkip="\\[[^\\]]*?\\]\\([^\\)]*?\\)|`[^`]*?`|<[^>]*?>",Ze._overlapSkip="__[^_]*?__|\\*\\*\\[^\\*\\]*?\\*\\*",Ze._comment=Ve(Ne._comment).replace("(?:--\x3e|$)","--\x3e").getRegex(),Ze.em.start=Ve(Ze.em.start).replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.em.middle=Ve(Ze.em.middle).replace(/punctuation/g,Ze._punctuation).replace(/overlapSkip/g,Ze._overlapSkip).getRegex(),Ze.em.endAst=Ve(Ze.em.endAst,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.em.endUnd=Ve(Ze.em.endUnd,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.strong.start=Ve(Ze.strong.start).replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.strong.middle=Ve(Ze.strong.middle).replace(/punctuation/g,Ze._punctuation).replace(/overlapSkip/g,Ze._overlapSkip).getRegex(),Ze.strong.endAst=Ve(Ze.strong.endAst,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.strong.endUnd=Ve(Ze.strong.endUnd,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.blockSkip=Ve(Ze._blockSkip,"g").getRegex(),Ze.overlapSkip=Ve(Ze._overlapSkip,"g").getRegex(),Ze._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,Ze._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,Ze._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,Ze.autolink=Ve(Ze.autolink).replace("scheme",Ze._scheme).replace("email",Ze._email).getRegex(),Ze._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,Ze.tag=Ve(Ze.tag).replace("comment",Ze._comment).replace("attribute",Ze._attribute).getRegex(),Ze._label=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,Ze._href=/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/,Ze._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,Ze.link=Ve(Ze.link).replace("label",Ze._label).replace("href",Ze._href).replace("title",Ze._title).getRegex(),Ze.reflink=Ve(Ze.reflink).replace("label",Ze._label).getRegex(),Ze.reflinkSearch=Ve(Ze.reflinkSearch,"g").replace("reflink",Ze.reflink).replace("nolink",Ze.nolink).getRegex(),Ze.normal=De({},Ze),Ze.pedantic=De({},Ze.normal,{strong:{start:/^__|\*\*/,middle:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,endAst:/\*\*(?!\*)/g,endUnd:/__(?!_)/g},em:{start:/^_|\*/,middle:/^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,endAst:/\*(?!\*)/g,endUnd:/_(?!_)/g},link:Ve(/^!?\[(label)\]\((.*?)\)/).replace("label",Ze._label).getRegex(),reflink:Ve(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",Ze._label).getRegex()}),Ze.gfm=De({},Ze.normal,{escape:Ve(Ze.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/}),Ze.gfm.url=Ve(Ze.gfm.url,"i").replace("email",Ze.gfm._extended_email).getRegex(),Ze.breaks=De({},Ze.gfm,{br:Ve(Ze.br).replace("{2,}","*").getRegex(),text:Ve(Ze.gfm.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()});var Ze={block:Ne,inline:Ze},on=we.defaults,tn=Ze.block,an=Ze.inline,rn=Ge;function cn(e){return e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")}function un(e){for(var n,i="",o=e.length,t=0;t<o;t++)n=e.charCodeAt(t),i+="&#"+(n=.5<Math.random()?"x"+n.toString(16):n)+";";return i}var fn=function(){function i(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||on,this.options.tokenizer=this.options.tokenizer||new nn,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options;e={block:tn.normal,inline:an.normal};this.options.pedantic?(e.block=tn.pedantic,e.inline=an.pedantic):this.options.gfm&&(e.block=tn.gfm,this.options.breaks?e.inline=an.breaks:e.inline=an.gfm),this.tokenizer.rules=e}var e={rules:{configurable:!0}};return e.rules.get=function(){return{block:tn,inline:an}},i.lex=function(e,n){return new i(n).lex(e)},i.lexInline=function(e,n){return new i(n).inlineTokens(e)},i.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," "),this.blockTokens(e,this.tokens,!0),this.inline(this.tokens),this.tokens},i.prototype.blockTokens=function(e,n,i){var o,t,a,r;for(void 0===n&&(n=[]),void 0===i&&(i=!0),this.options.pedantic&&(e=e.replace(/^ +$/gm,""));e;)if(o=this.tokenizer.space(e))e=e.substring(o.raw.length),o.type&&n.push(o);else if(o=this.tokenizer.code(e,n))e=e.substring(o.raw.length),o.type?n.push(o):((r=n[n.length-1]).raw+="\n"+o.raw,r.text+="\n"+o.text);else if(o=this.tokenizer.fences(e))e=e.substring(o.raw.length),n.push(o);else if(o=this.tokenizer.heading(e))e=e.substring(o.raw.length),n.push(o);else if(o=this.tokenizer.nptable(e))e=e.substring(o.raw.length),n.push(o);else if(o=this.tokenizer.hr(e))e=e.substring(o.raw.length),n.push(o);else if(o=this.tokenizer.blockquote(e))e=e.substring(o.raw.length),o.tokens=this.blockTokens(o.text,[],i),n.push(o);else if(o=this.tokenizer.list(e)){for(e=e.substring(o.raw.length),a=o.items.length,t=0;t<a;t++)o.items[t].tokens=this.blockTokens(o.items[t].text,[],!1);n.push(o)}else if(o=this.tokenizer.html(e))e=e.substring(o.raw.length),n.push(o);else if(i&&(o=this.tokenizer.def(e)))e=e.substring(o.raw.length),this.tokens.links[o.tag]||(this.tokens.links[o.tag]={href:o.href,title:o.title});else if(o=this.tokenizer.table(e))e=e.substring(o.raw.length),n.push(o);else if(o=this.tokenizer.lheading(e))e=e.substring(o.raw.length),n.push(o);else if(i&&(o=this.tokenizer.paragraph(e)))e=e.substring(o.raw.length),n.push(o);else if(o=this.tokenizer.text(e,n))e=e.substring(o.raw.length),o.type?n.push(o):((r=n[n.length-1]).raw+="\n"+o.raw,r.text+="\n"+o.text);else if(e){var c="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(c);break}throw new Error(c)}return n},i.prototype.inline=function(e){for(var n,i,o,t,a,r=e.length,c=0;c<r;c++)switch((a=e[c]).type){case"paragraph":case"text":case"heading":a.tokens=[],this.inlineTokens(a.text,a.tokens);break;case"table":for(a.tokens={header:[],cells:[]},o=a.header.length,n=0;n<o;n++)a.tokens.header[n]=[],this.inlineTokens(a.header[n],a.tokens.header[n]);for(o=a.cells.length,n=0;n<o;n++)for(t=a.cells[n],a.tokens.cells[n]=[],i=0;i<t.length;i++)a.tokens.cells[n][i]=[],this.inlineTokens(t[i],a.tokens.cells[n][i]);break;case"blockquote":this.inline(a.tokens);break;case"list":for(o=a.items.length,n=0;n<o;n++)this.inline(a.items[n].tokens)}return e},i.prototype.inlineTokens=function(e,n,i,o){var t;void 0===n&&(n=[]),void 0===i&&(i=!1),void 0===o&&(o=!1);var a,r,c,u=e;if(this.tokens.links){var f=Object.keys(this.tokens.links);if(0<f.length)for(;null!=(a=this.tokenizer.rules.inline.reflinkSearch.exec(u));)f.includes(a[0].slice(a[0].lastIndexOf("[")+1,-1))&&(u=u.slice(0,a.index)+"["+rn("a",a[0].length-2)+"]"+u.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(a=this.tokenizer.rules.inline.blockSkip.exec(u));)u=u.slice(0,a.index)+"["+rn("a",a[0].length-2)+"]"+u.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;e;)if(r||(c=""),r=!1,t=this.tokenizer.escape(e))e=e.substring(t.raw.length),n.push(t);else if(t=this.tokenizer.tag(e,i,o))e=e.substring(t.raw.length),i=t.inLink,o=t.inRawBlock,n.push(t);else if(t=this.tokenizer.link(e))e=e.substring(t.raw.length),"link"===t.type&&(t.tokens=this.inlineTokens(t.text,[],!0,o)),n.push(t);else if(t=this.tokenizer.reflink(e,this.tokens.links))e=e.substring(t.raw.length),"link"===t.type&&(t.tokens=this.inlineTokens(t.text,[],!0,o)),n.push(t);else if(t=this.tokenizer.strong(e,u,c))e=e.substring(t.raw.length),t.tokens=this.inlineTokens(t.text,[],i,o),n.push(t);else if(t=this.tokenizer.em(e,u,c))e=e.substring(t.raw.length),t.tokens=this.inlineTokens(t.text,[],i,o),n.push(t);else if(t=this.tokenizer.codespan(e))e=e.substring(t.raw.length),n.push(t);else if(t=this.tokenizer.br(e))e=e.substring(t.raw.length),n.push(t);else if(t=this.tokenizer.del(e))e=e.substring(t.raw.length),t.tokens=this.inlineTokens(t.text,[],i,o),n.push(t);else if(t=this.tokenizer.autolink(e,un))e=e.substring(t.raw.length),n.push(t);else if(i||!(t=this.tokenizer.url(e,un))){if(t=this.tokenizer.inlineText(e,o,cn))e=e.substring(t.raw.length),c=t.raw.slice(-1),r=!0,n.push(t);else if(e){var p="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(p);break}throw new Error(p)}}else e=e.substring(t.raw.length),n.push(t);return n},Object.defineProperties(i,e),i}(),pn=we.defaults,dn=He,gn=Me,sn=function(){function e(e){this.options=e||pn}return e.prototype.code=function(e,n,i){var o=(n||"").match(/\S*/)[0];return!this.options.highlight||null!=(n=this.options.highlight(e,o))&&n!==e&&(i=!0,e=n),e=e.replace(/\n$/,"")+"\n",o?'<pre><code class="'+this.options.langPrefix+gn(o,!0)+'">'+(i?e:gn(e,!0))+"</code></pre>\n":"<pre><code>"+(i?e:gn(e,!0))+"</code></pre>\n"},e.prototype.blockquote=function(e){return"<blockquote>\n"+e+"</blockquote>\n"},e.prototype.html=function(e){return e},e.prototype.heading=function(e,n,i,o){return this.options.headerIds?"<h"+n+' id="'+this.options.headerPrefix+o.slug(i)+'">'+e+"</h"+n+">\n":"<h"+n+">"+e+"</h"+n+">\n"},e.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"},e.prototype.list=function(e,n,i){var o=n?"ol":"ul";return"<"+o+(n&&1!==i?' start="'+i+'"':"")+">\n"+e+"</"+o+">\n"},e.prototype.listitem=function(e){return"<li>"+e+"</li>\n"},e.prototype.checkbox=function(e){return"<input "+(e?'checked="" ':"")+'disabled="" type="checkbox"'+(this.options.xhtml?" /":"")+"> "},e.prototype.paragraph=function(e){return"<p>"+e+"</p>\n"},e.prototype.table=function(e,n){return"<table>\n<thead>\n"+e+"</thead>\n"+(n=n&&"<tbody>"+n+"</tbody>")+"</table>\n"},e.prototype.tablerow=function(e){return"<tr>\n"+e+"</tr>\n"},e.prototype.tablecell=function(e,n){var i=n.header?"th":"td";return(n.align?"<"+i+' align="'+n.align+'">':"<"+i+">")+e+"</"+i+">\n"},e.prototype.strong=function(e){return"<strong>"+e+"</strong>"},e.prototype.em=function(e){return"<em>"+e+"</em>"},e.prototype.codespan=function(e){return"<code>"+e+"</code>"},e.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"},e.prototype.del=function(e){return"<del>"+e+"</del>"},e.prototype.link=function(e,n,i){if(null===(e=dn(this.options.sanitize,this.options.baseUrl,e)))return i;e='<a href="'+gn(e)+'"';return n&&(e+=' title="'+n+'"'),e+=">"+i+"</a>"},e.prototype.image=function(e,n,i){if(null===(e=dn(this.options.sanitize,this.options.baseUrl,e)))return i;i='<img src="'+e+'" alt="'+i+'"';return n&&(i+=' title="'+n+'"'),i+=this.options.xhtml?"/>":">"},e.prototype.text=function(e){return e},e}(),ln=function(){function e(){}return e.prototype.strong=function(e){return e},e.prototype.em=function(e){return e},e.prototype.codespan=function(e){return e},e.prototype.del=function(e){return e},e.prototype.html=function(e){return e},e.prototype.text=function(e){return e},e.prototype.link=function(e,n,i){return""+i},e.prototype.image=function(e,n,i){return""+i},e.prototype.br=function(){return""},e}(),vn=function(){function e(){this.seen={}}return e.prototype.serialize=function(e){return e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-")},e.prototype.getNextSafeSlug=function(e,n){var i=e,o=0;if(this.seen.hasOwnProperty(i))for(o=this.seen[e];i=e+"-"+ ++o,this.seen.hasOwnProperty(i););return n||(this.seen[e]=o,this.seen[i]=0),i},e.prototype.slug=function(e,n){void 0===n&&(n={});e=this.serialize(e);return this.getNextSafeSlug(e,n.dryrun)},e}(),hn=we.defaults,_n=Ie,mn=function(){function i(e){this.options=e||hn,this.options.renderer=this.options.renderer||new sn,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new ln,this.slugger=new vn}return i.parse=function(e,n){return new i(n).parse(e)},i.parseInline=function(e,n){return new i(n).parseInline(e)},i.prototype.parse=function(e,n){void 0===n&&(n=!0);for(var i,o,t,a,r,c,u,f,p,d,g,s,l,v,h,_="",m=e.length,b=0;b<m;b++)switch((f=e[b]).type){case"space":continue;case"hr":_+=this.renderer.hr();continue;case"heading":_+=this.renderer.heading(this.parseInline(f.tokens),f.depth,_n(this.parseInline(f.tokens,this.textRenderer)),this.slugger);continue;case"code":_+=this.renderer.code(f.text,f.lang,f.escaped);continue;case"table":for(c=p="",t=f.header.length,i=0;i<t;i++)c+=this.renderer.tablecell(this.parseInline(f.tokens.header[i]),{header:!0,align:f.align[i]});for(p+=this.renderer.tablerow(c),u="",t=f.cells.length,i=0;i<t;i++){for(c="",a=(r=f.tokens.cells[i]).length,o=0;o<a;o++)c+=this.renderer.tablecell(this.parseInline(r[o]),{header:!1,align:f.align[o]});u+=this.renderer.tablerow(c)}_+=this.renderer.table(p,u);continue;case"blockquote":u=this.parse(f.tokens),_+=this.renderer.blockquote(u);continue;case"list":for(p=f.ordered,k=f.start,d=f.loose,t=f.items.length,u="",i=0;i<t;i++)l=(s=f.items[i]).checked,v=s.task,g="",s.task&&(h=this.renderer.checkbox(l),d?0<s.tokens.length&&"text"===s.tokens[0].type?(s.tokens[0].text=h+" "+s.tokens[0].text,s.tokens[0].tokens&&0<s.tokens[0].tokens.length&&"text"===s.tokens[0].tokens[0].type&&(s.tokens[0].tokens[0].text=h+" "+s.tokens[0].tokens[0].text)):s.tokens.unshift({type:"text",text:h}):g+=h),g+=this.parse(s.tokens,d),u+=this.renderer.listitem(g,v,l);_+=this.renderer.list(u,p,k);continue;case"html":_+=this.renderer.html(f.text);continue;case"paragraph":_+=this.renderer.paragraph(this.parseInline(f.tokens));continue;case"text":for(u=f.tokens?this.parseInline(f.tokens):f.text;b+1<m&&"text"===e[b+1].type;)u+="\n"+((f=e[++b]).tokens?this.parseInline(f.tokens):f.text);_+=n?this.renderer.paragraph(u):u;continue;default:var k='Token with "'+f.type+'" type was not found.';if(this.options.silent)return void console.error(k);throw new Error(k)}return _},i.prototype.parseInline=function(e,n){n=n||this.renderer;for(var i,o="",t=e.length,a=0;a<t;a++)switch((i=e[a]).type){case"escape":o+=n.text(i.text);break;case"html":o+=n.html(i.text);break;case"link":o+=n.link(i.href,i.title,this.parseInline(i.tokens,n));break;case"image":o+=n.image(i.href,i.title,i.text);break;case"strong":o+=n.strong(this.parseInline(i.tokens,n));break;case"em":o+=n.em(this.parseInline(i.tokens,n));break;case"codespan":o+=n.codespan(i.text);break;case"br":o+=n.br();break;case"del":o+=n.del(this.parseInline(i.tokens,n));break;case"text":o+=n.text(i.text);break;default:var r='Token with "'+i.type+'" type was not found.';if(this.options.silent)return void console.error(r);throw new Error(r)}return o},i}(),bn=Ue,kn=Ye,wn=Me,Me=we.getDefaults,yn=we.changeDefaults,we=we.defaults;function xn(e,i,o){if(null==e)throw new Error("marked(): input parameter is undefined or null");if("string"!=typeof e)throw new Error("marked(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected");if("function"==typeof i&&(o=i,i=null),i=bn({},xn.defaults,i||{}),kn(i),o){var t,a=i.highlight;try{t=fn.lex(e,i)}catch(e){return o(e)}function r(n){var e;if(!n)try{e=mn.parse(t,i)}catch(e){n=e}return i.highlight=a,n?o(n):o(null,e)}if(!a||a.length<3)return r();if(delete i.highlight,!t.length)return r();var c=0;return xn.walkTokens(t,function(i){"code"===i.type&&(c++,setTimeout(function(){a(i.text,i.lang,function(e,n){return e?r(e):(null!=n&&n!==i.text&&(i.text=n,i.escaped=!0),void(0===--c&&r()))})},0))}),void(0===c&&r())}try{var n=fn.lex(e,i);return i.walkTokens&&xn.walkTokens(n,i.walkTokens),mn.parse(n,i)}catch(e){if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",i.silent)return"<p>An error occurred:</p><pre>"+wn(e.message+"",!0)+"</pre>";throw e}}xn.options=xn.setOptions=function(e){return bn(xn.defaults,e),yn(xn.defaults),xn},xn.getDefaults=Me,xn.defaults=we,xn.use=function(a){var n,e=bn({},a);if(a.renderer){var i,r=xn.defaults.renderer||new sn;for(i in a.renderer)!function(o){var t=r[o];r[o]=function(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];var i=a.renderer[o].apply(r,e);return i=!1===i?t.apply(r,e):i}}(i);e.renderer=r}if(a.tokenizer){var t,c=xn.defaults.tokenizer||new nn;for(t in a.tokenizer)!function(){var o=c[t];c[t]=function(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];var i=a.tokenizer[t].apply(c,e);return i=!1===i?o.apply(c,e):i}}();e.tokenizer=c}a.walkTokens&&(n=xn.defaults.walkTokens,e.walkTokens=function(e){a.walkTokens(e),n&&n(e)}),xn.setOptions(e)},xn.walkTokens=function(e,n){for(var i=0,o=e;i<o.length;i+=1){var t=o[i];switch(n(t),t.type){case"table":for(var a=0,r=t.tokens.header;a<r.length;a+=1){var c=r[a];xn.walkTokens(c,n)}for(var u=0,f=t.tokens.cells;u<f.length;u+=1)for(var p=0,d=f[u];p<d.length;p+=1){var g=d[p];xn.walkTokens(g,n)}break;case"list":xn.walkTokens(t.items,n);break;default:t.tokens&&xn.walkTokens(t.tokens,n)}}},xn.parseInline=function(e,n){if(null==e)throw new Error("marked.parseInline(): input parameter is undefined or null");if("string"!=typeof e)throw new Error("marked.parseInline(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected");n=bn({},xn.defaults,n||{}),kn(n);try{var i=fn.lexInline(e,n);return n.walkTokens&&xn.walkTokens(i,n.walkTokens),mn.parseInline(i,n)}catch(e){if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",n.silent)return"<p>An error occurred:</p><pre>"+wn(e.message+"",!0)+"</pre>";throw e}},xn.Parser=mn,xn.parser=mn.parse,xn.Renderer=sn,xn.TextRenderer=ln,xn.Lexer=fn,xn.lexer=fn.lex,xn.Tokenizer=nn,xn.Slugger=vn;var Sn=xn.parse=xn;function An(e,i){if(void 0===i&&(i='<ul class="app-sub-sidebar">{inner}</ul>'),!e||!e.length)return"";var o="";return e.forEach(function(e){var n=e.title.replace(/(<([^>]+)>)/g,"");o+='<li><a class="section-link" href="'+e.slug+'" title="'+n+'">'+e.title+"</a></li>",e.children&&(o+=An(e.children,i))}),i.replace("{inner}",o)}function $n(e,n){return'<p class="'+e+'">'+n.slice(5).trim()+"</p>"}function zn(e,o){var t=[],a={};return e.forEach(function(e){var n=e.level||1,i=n-1;o<n||(a[i]?a[i].children=(a[i].children||[]).concat(e):t.push(e),a[n]=e)}),t}var Fn={},En=/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g;function Tn(e){return e.toLowerCase()}function Cn(e){if("string"!=typeof e)return"";var n=e.trim().replace(/[A-Z]+/g,Tn).replace(/<[^>]+>/g,"").replace(En,"").replace(/\s/g,"-").replace(/-+/g,"-").replace(/^(\d)/,"_$1"),e=Fn[n],e=u.call(Fn,n)?e+1:0;return n=(Fn[n]=e)?n+"-"+e:n}Cn.clear=function(){Fn={}};var Rn={baseURL:"https://github.githubassets.com/images/icons/emoji/",data:{100:"unicode/1f4af.png?v8",1234:"unicode/1f522.png?v8","+1":"unicode/1f44d.png?v8","-1":"unicode/1f44e.png?v8","1st_place_medal":"unicode/1f947.png?v8","2nd_place_medal":"unicode/1f948.png?v8","3rd_place_medal":"unicode/1f949.png?v8","8ball":"unicode/1f3b1.png?v8",a:"unicode/1f170.png?v8",ab:"unicode/1f18e.png?v8",abacus:"unicode/1f9ee.png?v8",abc:"unicode/1f524.png?v8",abcd:"unicode/1f521.png?v8",accept:"unicode/1f251.png?v8",accordion:"unicode/1fa97.png?v8",adhesive_bandage:"unicode/1fa79.png?v8",adult:"unicode/1f9d1.png?v8",aerial_tramway:"unicode/1f6a1.png?v8",afghanistan:"unicode/1f1e6-1f1eb.png?v8",airplane:"unicode/2708.png?v8",aland_islands:"unicode/1f1e6-1f1fd.png?v8",alarm_clock:"unicode/23f0.png?v8",albania:"unicode/1f1e6-1f1f1.png?v8",alembic:"unicode/2697.png?v8",algeria:"unicode/1f1e9-1f1ff.png?v8",alien:"unicode/1f47d.png?v8",ambulance:"unicode/1f691.png?v8",american_samoa:"unicode/1f1e6-1f1f8.png?v8",amphora:"unicode/1f3fa.png?v8",anatomical_heart:"unicode/1fac0.png?v8",anchor:"unicode/2693.png?v8",andorra:"unicode/1f1e6-1f1e9.png?v8",angel:"unicode/1f47c.png?v8",anger:"unicode/1f4a2.png?v8",angola:"unicode/1f1e6-1f1f4.png?v8",angry:"unicode/1f620.png?v8",anguilla:"unicode/1f1e6-1f1ee.png?v8",anguished:"unicode/1f627.png?v8",ant:"unicode/1f41c.png?v8",antarctica:"unicode/1f1e6-1f1f6.png?v8",antigua_barbuda:"unicode/1f1e6-1f1ec.png?v8",apple:"unicode/1f34e.png?v8",aquarius:"unicode/2652.png?v8",argentina:"unicode/1f1e6-1f1f7.png?v8",aries:"unicode/2648.png?v8",armenia:"unicode/1f1e6-1f1f2.png?v8",arrow_backward:"unicode/25c0.png?v8",arrow_double_down:"unicode/23ec.png?v8",arrow_double_up:"unicode/23eb.png?v8",arrow_down:"unicode/2b07.png?v8",arrow_down_small:"unicode/1f53d.png?v8",arrow_forward:"unicode/25b6.png?v8",arrow_heading_down:"unicode/2935.png?v8",arrow_heading_up:"unicode/2934.png?v8",arrow_left:"unicode/2b05.png?v8",arrow_lower_left:"unicode/2199.png?v8",arrow_lower_right:"unicode/2198.png?v8",arrow_right:"unicode/27a1.png?v8",arrow_right_hook:"unicode/21aa.png?v8",arrow_up:"unicode/2b06.png?v8",arrow_up_down:"unicode/2195.png?v8",arrow_up_small:"unicode/1f53c.png?v8",arrow_upper_left:"unicode/2196.png?v8",arrow_upper_right:"unicode/2197.png?v8",arrows_clockwise:"unicode/1f503.png?v8",arrows_counterclockwise:"unicode/1f504.png?v8",art:"unicode/1f3a8.png?v8",articulated_lorry:"unicode/1f69b.png?v8",artificial_satellite:"unicode/1f6f0.png?v8",artist:"unicode/1f9d1-1f3a8.png?v8",aruba:"unicode/1f1e6-1f1fc.png?v8",ascension_island:"unicode/1f1e6-1f1e8.png?v8",asterisk:"unicode/002a-20e3.png?v8",astonished:"unicode/1f632.png?v8",astronaut:"unicode/1f9d1-1f680.png?v8",athletic_shoe:"unicode/1f45f.png?v8",atm:"unicode/1f3e7.png?v8",atom:"atom.png?v8",atom_symbol:"unicode/269b.png?v8",australia:"unicode/1f1e6-1f1fa.png?v8",austria:"unicode/1f1e6-1f1f9.png?v8",auto_rickshaw:"unicode/1f6fa.png?v8",avocado:"unicode/1f951.png?v8",axe:"unicode/1fa93.png?v8",azerbaijan:"unicode/1f1e6-1f1ff.png?v8",b:"unicode/1f171.png?v8",baby:"unicode/1f476.png?v8",baby_bottle:"unicode/1f37c.png?v8",baby_chick:"unicode/1f424.png?v8",baby_symbol:"unicode/1f6bc.png?v8",back:"unicode/1f519.png?v8",bacon:"unicode/1f953.png?v8",badger:"unicode/1f9a1.png?v8",badminton:"unicode/1f3f8.png?v8",bagel:"unicode/1f96f.png?v8",baggage_claim:"unicode/1f6c4.png?v8",baguette_bread:"unicode/1f956.png?v8",bahamas:"unicode/1f1e7-1f1f8.png?v8",bahrain:"unicode/1f1e7-1f1ed.png?v8",balance_scale:"unicode/2696.png?v8",bald_man:"unicode/1f468-1f9b2.png?v8",bald_woman:"unicode/1f469-1f9b2.png?v8",ballet_shoes:"unicode/1fa70.png?v8",balloon:"unicode/1f388.png?v8",ballot_box:"unicode/1f5f3.png?v8",ballot_box_with_check:"unicode/2611.png?v8",bamboo:"unicode/1f38d.png?v8",banana:"unicode/1f34c.png?v8",bangbang:"unicode/203c.png?v8",bangladesh:"unicode/1f1e7-1f1e9.png?v8",banjo:"unicode/1fa95.png?v8",bank:"unicode/1f3e6.png?v8",bar_chart:"unicode/1f4ca.png?v8",barbados:"unicode/1f1e7-1f1e7.png?v8",barber:"unicode/1f488.png?v8",baseball:"unicode/26be.png?v8",basecamp:"basecamp.png?v8",basecampy:"basecampy.png?v8",basket:"unicode/1f9fa.png?v8",basketball:"unicode/1f3c0.png?v8",basketball_man:"unicode/26f9-2642.png?v8",basketball_woman:"unicode/26f9-2640.png?v8",bat:"unicode/1f987.png?v8",bath:"unicode/1f6c0.png?v8",bathtub:"unicode/1f6c1.png?v8",battery:"unicode/1f50b.png?v8",beach_umbrella:"unicode/1f3d6.png?v8",bear:"unicode/1f43b.png?v8",bearded_person:"unicode/1f9d4.png?v8",beaver:"unicode/1f9ab.png?v8",bed:"unicode/1f6cf.png?v8",bee:"unicode/1f41d.png?v8",beer:"unicode/1f37a.png?v8",beers:"unicode/1f37b.png?v8",beetle:"unicode/1fab2.png?v8",beginner:"unicode/1f530.png?v8",belarus:"unicode/1f1e7-1f1fe.png?v8",belgium:"unicode/1f1e7-1f1ea.png?v8",belize:"unicode/1f1e7-1f1ff.png?v8",bell:"unicode/1f514.png?v8",bell_pepper:"unicode/1fad1.png?v8",bellhop_bell:"unicode/1f6ce.png?v8",benin:"unicode/1f1e7-1f1ef.png?v8",bento:"unicode/1f371.png?v8",bermuda:"unicode/1f1e7-1f1f2.png?v8",beverage_box:"unicode/1f9c3.png?v8",bhutan:"unicode/1f1e7-1f1f9.png?v8",bicyclist:"unicode/1f6b4.png?v8",bike:"unicode/1f6b2.png?v8",biking_man:"unicode/1f6b4-2642.png?v8",biking_woman:"unicode/1f6b4-2640.png?v8",bikini:"unicode/1f459.png?v8",billed_cap:"unicode/1f9e2.png?v8",biohazard:"unicode/2623.png?v8",bird:"unicode/1f426.png?v8",birthday:"unicode/1f382.png?v8",bison:"unicode/1f9ac.png?v8",black_cat:"unicode/1f408-2b1b.png?v8",black_circle:"unicode/26ab.png?v8",black_flag:"unicode/1f3f4.png?v8",black_heart:"unicode/1f5a4.png?v8",black_joker:"unicode/1f0cf.png?v8",black_large_square:"unicode/2b1b.png?v8",black_medium_small_square:"unicode/25fe.png?v8",black_medium_square:"unicode/25fc.png?v8",black_nib:"unicode/2712.png?v8",black_small_square:"unicode/25aa.png?v8",black_square_button:"unicode/1f532.png?v8",blond_haired_man:"unicode/1f471-2642.png?v8",blond_haired_person:"unicode/1f471.png?v8",blond_haired_woman:"unicode/1f471-2640.png?v8",blonde_woman:"unicode/1f471-2640.png?v8",blossom:"unicode/1f33c.png?v8",blowfish:"unicode/1f421.png?v8",blue_book:"unicode/1f4d8.png?v8",blue_car:"unicode/1f699.png?v8",blue_heart:"unicode/1f499.png?v8",blue_square:"unicode/1f7e6.png?v8",blueberries:"unicode/1fad0.png?v8",blush:"unicode/1f60a.png?v8",boar:"unicode/1f417.png?v8",boat:"unicode/26f5.png?v8",bolivia:"unicode/1f1e7-1f1f4.png?v8",bomb:"unicode/1f4a3.png?v8",bone:"unicode/1f9b4.png?v8",book:"unicode/1f4d6.png?v8",bookmark:"unicode/1f516.png?v8",bookmark_tabs:"unicode/1f4d1.png?v8",books:"unicode/1f4da.png?v8",boom:"unicode/1f4a5.png?v8",boomerang:"unicode/1fa83.png?v8",boot:"unicode/1f462.png?v8",bosnia_herzegovina:"unicode/1f1e7-1f1e6.png?v8",botswana:"unicode/1f1e7-1f1fc.png?v8",bouncing_ball_man:"unicode/26f9-2642.png?v8",bouncing_ball_person:"unicode/26f9.png?v8",bouncing_ball_woman:"unicode/26f9-2640.png?v8",bouquet:"unicode/1f490.png?v8",bouvet_island:"unicode/1f1e7-1f1fb.png?v8",bow:"unicode/1f647.png?v8",bow_and_arrow:"unicode/1f3f9.png?v8",bowing_man:"unicode/1f647-2642.png?v8",bowing_woman:"unicode/1f647-2640.png?v8",bowl_with_spoon:"unicode/1f963.png?v8",bowling:"unicode/1f3b3.png?v8",bowtie:"bowtie.png?v8",boxing_glove:"unicode/1f94a.png?v8",boy:"unicode/1f466.png?v8",brain:"unicode/1f9e0.png?v8",brazil:"unicode/1f1e7-1f1f7.png?v8",bread:"unicode/1f35e.png?v8",breast_feeding:"unicode/1f931.png?v8",bricks:"unicode/1f9f1.png?v8",bride_with_veil:"unicode/1f470-2640.png?v8",bridge_at_night:"unicode/1f309.png?v8",briefcase:"unicode/1f4bc.png?v8",british_indian_ocean_territory:"unicode/1f1ee-1f1f4.png?v8",british_virgin_islands:"unicode/1f1fb-1f1ec.png?v8",broccoli:"unicode/1f966.png?v8",broken_heart:"unicode/1f494.png?v8",broom:"unicode/1f9f9.png?v8",brown_circle:"unicode/1f7e4.png?v8",brown_heart:"unicode/1f90e.png?v8",brown_square:"unicode/1f7eb.png?v8",brunei:"unicode/1f1e7-1f1f3.png?v8",bubble_tea:"unicode/1f9cb.png?v8",bucket:"unicode/1faa3.png?v8",bug:"unicode/1f41b.png?v8",building_construction:"unicode/1f3d7.png?v8",bulb:"unicode/1f4a1.png?v8",bulgaria:"unicode/1f1e7-1f1ec.png?v8",bullettrain_front:"unicode/1f685.png?v8",bullettrain_side:"unicode/1f684.png?v8",burkina_faso:"unicode/1f1e7-1f1eb.png?v8",burrito:"unicode/1f32f.png?v8",burundi:"unicode/1f1e7-1f1ee.png?v8",bus:"unicode/1f68c.png?v8",business_suit_levitating:"unicode/1f574.png?v8",busstop:"unicode/1f68f.png?v8",bust_in_silhouette:"unicode/1f464.png?v8",busts_in_silhouette:"unicode/1f465.png?v8",butter:"unicode/1f9c8.png?v8",butterfly:"unicode/1f98b.png?v8",cactus:"unicode/1f335.png?v8",cake:"unicode/1f370.png?v8",calendar:"unicode/1f4c6.png?v8",call_me_hand:"unicode/1f919.png?v8",calling:"unicode/1f4f2.png?v8",cambodia:"unicode/1f1f0-1f1ed.png?v8",camel:"unicode/1f42b.png?v8",camera:"unicode/1f4f7.png?v8",camera_flash:"unicode/1f4f8.png?v8",cameroon:"unicode/1f1e8-1f1f2.png?v8",camping:"unicode/1f3d5.png?v8",canada:"unicode/1f1e8-1f1e6.png?v8",canary_islands:"unicode/1f1ee-1f1e8.png?v8",cancer:"unicode/264b.png?v8",candle:"unicode/1f56f.png?v8",candy:"unicode/1f36c.png?v8",canned_food:"unicode/1f96b.png?v8",canoe:"unicode/1f6f6.png?v8",cape_verde:"unicode/1f1e8-1f1fb.png?v8",capital_abcd:"unicode/1f520.png?v8",capricorn:"unicode/2651.png?v8",car:"unicode/1f697.png?v8",card_file_box:"unicode/1f5c3.png?v8",card_index:"unicode/1f4c7.png?v8",card_index_dividers:"unicode/1f5c2.png?v8",caribbean_netherlands:"unicode/1f1e7-1f1f6.png?v8",carousel_horse:"unicode/1f3a0.png?v8",carpentry_saw:"unicode/1fa9a.png?v8",carrot:"unicode/1f955.png?v8",cartwheeling:"unicode/1f938.png?v8",cat:"unicode/1f431.png?v8",cat2:"unicode/1f408.png?v8",cayman_islands:"unicode/1f1f0-1f1fe.png?v8",cd:"unicode/1f4bf.png?v8",central_african_republic:"unicode/1f1e8-1f1eb.png?v8",ceuta_melilla:"unicode/1f1ea-1f1e6.png?v8",chad:"unicode/1f1f9-1f1e9.png?v8",chains:"unicode/26d3.png?v8",chair:"unicode/1fa91.png?v8",champagne:"unicode/1f37e.png?v8",chart:"unicode/1f4b9.png?v8",chart_with_downwards_trend:"unicode/1f4c9.png?v8",chart_with_upwards_trend:"unicode/1f4c8.png?v8",checkered_flag:"unicode/1f3c1.png?v8",cheese:"unicode/1f9c0.png?v8",cherries:"unicode/1f352.png?v8",cherry_blossom:"unicode/1f338.png?v8",chess_pawn:"unicode/265f.png?v8",chestnut:"unicode/1f330.png?v8",chicken:"unicode/1f414.png?v8",child:"unicode/1f9d2.png?v8",children_crossing:"unicode/1f6b8.png?v8",chile:"unicode/1f1e8-1f1f1.png?v8",chipmunk:"unicode/1f43f.png?v8",chocolate_bar:"unicode/1f36b.png?v8",chopsticks:"unicode/1f962.png?v8",christmas_island:"unicode/1f1e8-1f1fd.png?v8",christmas_tree:"unicode/1f384.png?v8",church:"unicode/26ea.png?v8",cinema:"unicode/1f3a6.png?v8",circus_tent:"unicode/1f3aa.png?v8",city_sunrise:"unicode/1f307.png?v8",city_sunset:"unicode/1f306.png?v8",cityscape:"unicode/1f3d9.png?v8",cl:"unicode/1f191.png?v8",clamp:"unicode/1f5dc.png?v8",clap:"unicode/1f44f.png?v8",clapper:"unicode/1f3ac.png?v8",classical_building:"unicode/1f3db.png?v8",climbing:"unicode/1f9d7.png?v8",climbing_man:"unicode/1f9d7-2642.png?v8",climbing_woman:"unicode/1f9d7-2640.png?v8",clinking_glasses:"unicode/1f942.png?v8",clipboard:"unicode/1f4cb.png?v8",clipperton_island:"unicode/1f1e8-1f1f5.png?v8",clock1:"unicode/1f550.png?v8",clock10:"unicode/1f559.png?v8",clock1030:"unicode/1f565.png?v8",clock11:"unicode/1f55a.png?v8",clock1130:"unicode/1f566.png?v8",clock12:"unicode/1f55b.png?v8",clock1230:"unicode/1f567.png?v8",clock130:"unicode/1f55c.png?v8",clock2:"unicode/1f551.png?v8",clock230:"unicode/1f55d.png?v8",clock3:"unicode/1f552.png?v8",clock330:"unicode/1f55e.png?v8",clock4:"unicode/1f553.png?v8",clock430:"unicode/1f55f.png?v8",clock5:"unicode/1f554.png?v8",clock530:"unicode/1f560.png?v8",clock6:"unicode/1f555.png?v8",clock630:"unicode/1f561.png?v8",clock7:"unicode/1f556.png?v8",clock730:"unicode/1f562.png?v8",clock8:"unicode/1f557.png?v8",clock830:"unicode/1f563.png?v8",clock9:"unicode/1f558.png?v8",clock930:"unicode/1f564.png?v8",closed_book:"unicode/1f4d5.png?v8",closed_lock_with_key:"unicode/1f510.png?v8",closed_umbrella:"unicode/1f302.png?v8",cloud:"unicode/2601.png?v8",cloud_with_lightning:"unicode/1f329.png?v8",cloud_with_lightning_and_rain:"unicode/26c8.png?v8",cloud_with_rain:"unicode/1f327.png?v8",cloud_with_snow:"unicode/1f328.png?v8",clown_face:"unicode/1f921.png?v8",clubs:"unicode/2663.png?v8",cn:"unicode/1f1e8-1f1f3.png?v8",coat:"unicode/1f9e5.png?v8",cockroach:"unicode/1fab3.png?v8",cocktail:"unicode/1f378.png?v8",coconut:"unicode/1f965.png?v8",cocos_islands:"unicode/1f1e8-1f1e8.png?v8",coffee:"unicode/2615.png?v8",coffin:"unicode/26b0.png?v8",coin:"unicode/1fa99.png?v8",cold_face:"unicode/1f976.png?v8",cold_sweat:"unicode/1f630.png?v8",collision:"unicode/1f4a5.png?v8",colombia:"unicode/1f1e8-1f1f4.png?v8",comet:"unicode/2604.png?v8",comoros:"unicode/1f1f0-1f1f2.png?v8",compass:"unicode/1f9ed.png?v8",computer:"unicode/1f4bb.png?v8",computer_mouse:"unicode/1f5b1.png?v8",confetti_ball:"unicode/1f38a.png?v8",confounded:"unicode/1f616.png?v8",confused:"unicode/1f615.png?v8",congo_brazzaville:"unicode/1f1e8-1f1ec.png?v8",congo_kinshasa:"unicode/1f1e8-1f1e9.png?v8",congratulations:"unicode/3297.png?v8",construction:"unicode/1f6a7.png?v8",construction_worker:"unicode/1f477.png?v8",construction_worker_man:"unicode/1f477-2642.png?v8",construction_worker_woman:"unicode/1f477-2640.png?v8",control_knobs:"unicode/1f39b.png?v8",convenience_store:"unicode/1f3ea.png?v8",cook:"unicode/1f9d1-1f373.png?v8",cook_islands:"unicode/1f1e8-1f1f0.png?v8",cookie:"unicode/1f36a.png?v8",cool:"unicode/1f192.png?v8",cop:"unicode/1f46e.png?v8",copyright:"unicode/00a9.png?v8",corn:"unicode/1f33d.png?v8",costa_rica:"unicode/1f1e8-1f1f7.png?v8",cote_divoire:"unicode/1f1e8-1f1ee.png?v8",couch_and_lamp:"unicode/1f6cb.png?v8",couple:"unicode/1f46b.png?v8",couple_with_heart:"unicode/1f491.png?v8",couple_with_heart_man_man:"unicode/1f468-2764-1f468.png?v8",couple_with_heart_woman_man:"unicode/1f469-2764-1f468.png?v8",couple_with_heart_woman_woman:"unicode/1f469-2764-1f469.png?v8",couplekiss:"unicode/1f48f.png?v8",couplekiss_man_man:"unicode/1f468-2764-1f48b-1f468.png?v8",couplekiss_man_woman:"unicode/1f469-2764-1f48b-1f468.png?v8",couplekiss_woman_woman:"unicode/1f469-2764-1f48b-1f469.png?v8",cow:"unicode/1f42e.png?v8",cow2:"unicode/1f404.png?v8",cowboy_hat_face:"unicode/1f920.png?v8",crab:"unicode/1f980.png?v8",crayon:"unicode/1f58d.png?v8",credit_card:"unicode/1f4b3.png?v8",crescent_moon:"unicode/1f319.png?v8",cricket:"unicode/1f997.png?v8",cricket_game:"unicode/1f3cf.png?v8",croatia:"unicode/1f1ed-1f1f7.png?v8",crocodile:"unicode/1f40a.png?v8",croissant:"unicode/1f950.png?v8",crossed_fingers:"unicode/1f91e.png?v8",crossed_flags:"unicode/1f38c.png?v8",crossed_swords:"unicode/2694.png?v8",crown:"unicode/1f451.png?v8",cry:"unicode/1f622.png?v8",crying_cat_face:"unicode/1f63f.png?v8",crystal_ball:"unicode/1f52e.png?v8",cuba:"unicode/1f1e8-1f1fa.png?v8",cucumber:"unicode/1f952.png?v8",cup_with_straw:"unicode/1f964.png?v8",cupcake:"unicode/1f9c1.png?v8",cupid:"unicode/1f498.png?v8",curacao:"unicode/1f1e8-1f1fc.png?v8",curling_stone:"unicode/1f94c.png?v8",curly_haired_man:"unicode/1f468-1f9b1.png?v8",curly_haired_woman:"unicode/1f469-1f9b1.png?v8",curly_loop:"unicode/27b0.png?v8",currency_exchange:"unicode/1f4b1.png?v8",curry:"unicode/1f35b.png?v8",cursing_face:"unicode/1f92c.png?v8",custard:"unicode/1f36e.png?v8",customs:"unicode/1f6c3.png?v8",cut_of_meat:"unicode/1f969.png?v8",cyclone:"unicode/1f300.png?v8",cyprus:"unicode/1f1e8-1f1fe.png?v8",czech_republic:"unicode/1f1e8-1f1ff.png?v8",dagger:"unicode/1f5e1.png?v8",dancer:"unicode/1f483.png?v8",dancers:"unicode/1f46f.png?v8",dancing_men:"unicode/1f46f-2642.png?v8",dancing_women:"unicode/1f46f-2640.png?v8",dango:"unicode/1f361.png?v8",dark_sunglasses:"unicode/1f576.png?v8",dart:"unicode/1f3af.png?v8",dash:"unicode/1f4a8.png?v8",date:"unicode/1f4c5.png?v8",de:"unicode/1f1e9-1f1ea.png?v8",deaf_man:"unicode/1f9cf-2642.png?v8",deaf_person:"unicode/1f9cf.png?v8",deaf_woman:"unicode/1f9cf-2640.png?v8",deciduous_tree:"unicode/1f333.png?v8",deer:"unicode/1f98c.png?v8",denmark:"unicode/1f1e9-1f1f0.png?v8",department_store:"unicode/1f3ec.png?v8",derelict_house:"unicode/1f3da.png?v8",desert:"unicode/1f3dc.png?v8",desert_island:"unicode/1f3dd.png?v8",desktop_computer:"unicode/1f5a5.png?v8",detective:"unicode/1f575.png?v8",diamond_shape_with_a_dot_inside:"unicode/1f4a0.png?v8",diamonds:"unicode/2666.png?v8",diego_garcia:"unicode/1f1e9-1f1ec.png?v8",disappointed:"unicode/1f61e.png?v8",disappointed_relieved:"unicode/1f625.png?v8",disguised_face:"unicode/1f978.png?v8",diving_mask:"unicode/1f93f.png?v8",diya_lamp:"unicode/1fa94.png?v8",dizzy:"unicode/1f4ab.png?v8",dizzy_face:"unicode/1f635.png?v8",djibouti:"unicode/1f1e9-1f1ef.png?v8",dna:"unicode/1f9ec.png?v8",do_not_litter:"unicode/1f6af.png?v8",dodo:"unicode/1f9a4.png?v8",dog:"unicode/1f436.png?v8",dog2:"unicode/1f415.png?v8",dollar:"unicode/1f4b5.png?v8",dolls:"unicode/1f38e.png?v8",dolphin:"unicode/1f42c.png?v8",dominica:"unicode/1f1e9-1f1f2.png?v8",dominican_republic:"unicode/1f1e9-1f1f4.png?v8",door:"unicode/1f6aa.png?v8",doughnut:"unicode/1f369.png?v8",dove:"unicode/1f54a.png?v8",dragon:"unicode/1f409.png?v8",dragon_face:"unicode/1f432.png?v8",dress:"unicode/1f457.png?v8",dromedary_camel:"unicode/1f42a.png?v8",drooling_face:"unicode/1f924.png?v8",drop_of_blood:"unicode/1fa78.png?v8",droplet:"unicode/1f4a7.png?v8",drum:"unicode/1f941.png?v8",duck:"unicode/1f986.png?v8",dumpling:"unicode/1f95f.png?v8",dvd:"unicode/1f4c0.png?v8","e-mail":"unicode/1f4e7.png?v8",eagle:"unicode/1f985.png?v8",ear:"unicode/1f442.png?v8",ear_of_rice:"unicode/1f33e.png?v8",ear_with_hearing_aid:"unicode/1f9bb.png?v8",earth_africa:"unicode/1f30d.png?v8",earth_americas:"unicode/1f30e.png?v8",earth_asia:"unicode/1f30f.png?v8",ecuador:"unicode/1f1ea-1f1e8.png?v8",egg:"unicode/1f95a.png?v8",eggplant:"unicode/1f346.png?v8",egypt:"unicode/1f1ea-1f1ec.png?v8",eight:"unicode/0038-20e3.png?v8",eight_pointed_black_star:"unicode/2734.png?v8",eight_spoked_asterisk:"unicode/2733.png?v8",eject_button:"unicode/23cf.png?v8",el_salvador:"unicode/1f1f8-1f1fb.png?v8",electric_plug:"unicode/1f50c.png?v8",electron:"electron.png?v8",elephant:"unicode/1f418.png?v8",elevator:"unicode/1f6d7.png?v8",elf:"unicode/1f9dd.png?v8",elf_man:"unicode/1f9dd-2642.png?v8",elf_woman:"unicode/1f9dd-2640.png?v8",email:"unicode/1f4e7.png?v8",end:"unicode/1f51a.png?v8",england:"unicode/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png?v8",envelope:"unicode/2709.png?v8",envelope_with_arrow:"unicode/1f4e9.png?v8",equatorial_guinea:"unicode/1f1ec-1f1f6.png?v8",eritrea:"unicode/1f1ea-1f1f7.png?v8",es:"unicode/1f1ea-1f1f8.png?v8",estonia:"unicode/1f1ea-1f1ea.png?v8",ethiopia:"unicode/1f1ea-1f1f9.png?v8",eu:"unicode/1f1ea-1f1fa.png?v8",euro:"unicode/1f4b6.png?v8",european_castle:"unicode/1f3f0.png?v8",european_post_office:"unicode/1f3e4.png?v8",european_union:"unicode/1f1ea-1f1fa.png?v8",evergreen_tree:"unicode/1f332.png?v8",exclamation:"unicode/2757.png?v8",exploding_head:"unicode/1f92f.png?v8",expressionless:"unicode/1f611.png?v8",eye:"unicode/1f441.png?v8",eye_speech_bubble:"unicode/1f441-1f5e8.png?v8",eyeglasses:"unicode/1f453.png?v8",eyes:"unicode/1f440.png?v8",face_exhaling:"unicode/1f62e-1f4a8.png?v8",face_in_clouds:"unicode/1f636-1f32b.png?v8",face_with_head_bandage:"unicode/1f915.png?v8",face_with_spiral_eyes:"unicode/1f635-1f4ab.png?v8",face_with_thermometer:"unicode/1f912.png?v8",facepalm:"unicode/1f926.png?v8",facepunch:"unicode/1f44a.png?v8",factory:"unicode/1f3ed.png?v8",factory_worker:"unicode/1f9d1-1f3ed.png?v8",fairy:"unicode/1f9da.png?v8",fairy_man:"unicode/1f9da-2642.png?v8",fairy_woman:"unicode/1f9da-2640.png?v8",falafel:"unicode/1f9c6.png?v8",falkland_islands:"unicode/1f1eb-1f1f0.png?v8",fallen_leaf:"unicode/1f342.png?v8",family:"unicode/1f46a.png?v8",family_man_boy:"unicode/1f468-1f466.png?v8",family_man_boy_boy:"unicode/1f468-1f466-1f466.png?v8",family_man_girl:"unicode/1f468-1f467.png?v8",family_man_girl_boy:"unicode/1f468-1f467-1f466.png?v8",family_man_girl_girl:"unicode/1f468-1f467-1f467.png?v8",family_man_man_boy:"unicode/1f468-1f468-1f466.png?v8",family_man_man_boy_boy:"unicode/1f468-1f468-1f466-1f466.png?v8",family_man_man_girl:"unicode/1f468-1f468-1f467.png?v8",family_man_man_girl_boy:"unicode/1f468-1f468-1f467-1f466.png?v8",family_man_man_girl_girl:"unicode/1f468-1f468-1f467-1f467.png?v8",family_man_woman_boy:"unicode/1f468-1f469-1f466.png?v8",family_man_woman_boy_boy:"unicode/1f468-1f469-1f466-1f466.png?v8",family_man_woman_girl:"unicode/1f468-1f469-1f467.png?v8",family_man_woman_girl_boy:"unicode/1f468-1f469-1f467-1f466.png?v8",family_man_woman_girl_girl:"unicode/1f468-1f469-1f467-1f467.png?v8",family_woman_boy:"unicode/1f469-1f466.png?v8",family_woman_boy_boy:"unicode/1f469-1f466-1f466.png?v8",family_woman_girl:"unicode/1f469-1f467.png?v8",family_woman_girl_boy:"unicode/1f469-1f467-1f466.png?v8",family_woman_girl_girl:"unicode/1f469-1f467-1f467.png?v8",family_woman_woman_boy:"unicode/1f469-1f469-1f466.png?v8",family_woman_woman_boy_boy:"unicode/1f469-1f469-1f466-1f466.png?v8",family_woman_woman_girl:"unicode/1f469-1f469-1f467.png?v8",family_woman_woman_girl_boy:"unicode/1f469-1f469-1f467-1f466.png?v8",family_woman_woman_girl_girl:"unicode/1f469-1f469-1f467-1f467.png?v8",farmer:"unicode/1f9d1-1f33e.png?v8",faroe_islands:"unicode/1f1eb-1f1f4.png?v8",fast_forward:"unicode/23e9.png?v8",fax:"unicode/1f4e0.png?v8",fearful:"unicode/1f628.png?v8",feather:"unicode/1fab6.png?v8",feelsgood:"feelsgood.png?v8",feet:"unicode/1f43e.png?v8",female_detective:"unicode/1f575-2640.png?v8",female_sign:"unicode/2640.png?v8",ferris_wheel:"unicode/1f3a1.png?v8",ferry:"unicode/26f4.png?v8",field_hockey:"unicode/1f3d1.png?v8",fiji:"unicode/1f1eb-1f1ef.png?v8",file_cabinet:"unicode/1f5c4.png?v8",file_folder:"unicode/1f4c1.png?v8",film_projector:"unicode/1f4fd.png?v8",film_strip:"unicode/1f39e.png?v8",finland:"unicode/1f1eb-1f1ee.png?v8",finnadie:"finnadie.png?v8",fire:"unicode/1f525.png?v8",fire_engine:"unicode/1f692.png?v8",fire_extinguisher:"unicode/1f9ef.png?v8",firecracker:"unicode/1f9e8.png?v8",firefighter:"unicode/1f9d1-1f692.png?v8",fireworks:"unicode/1f386.png?v8",first_quarter_moon:"unicode/1f313.png?v8",first_quarter_moon_with_face:"unicode/1f31b.png?v8",fish:"unicode/1f41f.png?v8",fish_cake:"unicode/1f365.png?v8",fishing_pole_and_fish:"unicode/1f3a3.png?v8",fist:"unicode/270a.png?v8",fist_left:"unicode/1f91b.png?v8",fist_oncoming:"unicode/1f44a.png?v8",fist_raised:"unicode/270a.png?v8",fist_right:"unicode/1f91c.png?v8",five:"unicode/0035-20e3.png?v8",flags:"unicode/1f38f.png?v8",flamingo:"unicode/1f9a9.png?v8",flashlight:"unicode/1f526.png?v8",flat_shoe:"unicode/1f97f.png?v8",flatbread:"unicode/1fad3.png?v8",fleur_de_lis:"unicode/269c.png?v8",flight_arrival:"unicode/1f6ec.png?v8",flight_departure:"unicode/1f6eb.png?v8",flipper:"unicode/1f42c.png?v8",floppy_disk:"unicode/1f4be.png?v8",flower_playing_cards:"unicode/1f3b4.png?v8",flushed:"unicode/1f633.png?v8",fly:"unicode/1fab0.png?v8",flying_disc:"unicode/1f94f.png?v8",flying_saucer:"unicode/1f6f8.png?v8",fog:"unicode/1f32b.png?v8",foggy:"unicode/1f301.png?v8",fondue:"unicode/1fad5.png?v8",foot:"unicode/1f9b6.png?v8",football:"unicode/1f3c8.png?v8",footprints:"unicode/1f463.png?v8",fork_and_knife:"unicode/1f374.png?v8",fortune_cookie:"unicode/1f960.png?v8",fountain:"unicode/26f2.png?v8",fountain_pen:"unicode/1f58b.png?v8",four:"unicode/0034-20e3.png?v8",four_leaf_clover:"unicode/1f340.png?v8",fox_face:"unicode/1f98a.png?v8",fr:"unicode/1f1eb-1f1f7.png?v8",framed_picture:"unicode/1f5bc.png?v8",free:"unicode/1f193.png?v8",french_guiana:"unicode/1f1ec-1f1eb.png?v8",french_polynesia:"unicode/1f1f5-1f1eb.png?v8",french_southern_territories:"unicode/1f1f9-1f1eb.png?v8",fried_egg:"unicode/1f373.png?v8",fried_shrimp:"unicode/1f364.png?v8",fries:"unicode/1f35f.png?v8",frog:"unicode/1f438.png?v8",frowning:"unicode/1f626.png?v8",frowning_face:"unicode/2639.png?v8",frowning_man:"unicode/1f64d-2642.png?v8",frowning_person:"unicode/1f64d.png?v8",frowning_woman:"unicode/1f64d-2640.png?v8",fu:"unicode/1f595.png?v8",fuelpump:"unicode/26fd.png?v8",full_moon:"unicode/1f315.png?v8",full_moon_with_face:"unicode/1f31d.png?v8",funeral_urn:"unicode/26b1.png?v8",gabon:"unicode/1f1ec-1f1e6.png?v8",gambia:"unicode/1f1ec-1f1f2.png?v8",game_die:"unicode/1f3b2.png?v8",garlic:"unicode/1f9c4.png?v8",gb:"unicode/1f1ec-1f1e7.png?v8",gear:"unicode/2699.png?v8",gem:"unicode/1f48e.png?v8",gemini:"unicode/264a.png?v8",genie:"unicode/1f9de.png?v8",genie_man:"unicode/1f9de-2642.png?v8",genie_woman:"unicode/1f9de-2640.png?v8",georgia:"unicode/1f1ec-1f1ea.png?v8",ghana:"unicode/1f1ec-1f1ed.png?v8",ghost:"unicode/1f47b.png?v8",gibraltar:"unicode/1f1ec-1f1ee.png?v8",gift:"unicode/1f381.png?v8",gift_heart:"unicode/1f49d.png?v8",giraffe:"unicode/1f992.png?v8",girl:"unicode/1f467.png?v8",globe_with_meridians:"unicode/1f310.png?v8",gloves:"unicode/1f9e4.png?v8",goal_net:"unicode/1f945.png?v8",goat:"unicode/1f410.png?v8",goberserk:"goberserk.png?v8",godmode:"godmode.png?v8",goggles:"unicode/1f97d.png?v8",golf:"unicode/26f3.png?v8",golfing:"unicode/1f3cc.png?v8",golfing_man:"unicode/1f3cc-2642.png?v8",golfing_woman:"unicode/1f3cc-2640.png?v8",gorilla:"unicode/1f98d.png?v8",grapes:"unicode/1f347.png?v8",greece:"unicode/1f1ec-1f1f7.png?v8",green_apple:"unicode/1f34f.png?v8",green_book:"unicode/1f4d7.png?v8",green_circle:"unicode/1f7e2.png?v8",green_heart:"unicode/1f49a.png?v8",green_salad:"unicode/1f957.png?v8",green_square:"unicode/1f7e9.png?v8",greenland:"unicode/1f1ec-1f1f1.png?v8",grenada:"unicode/1f1ec-1f1e9.png?v8",grey_exclamation:"unicode/2755.png?v8",grey_question:"unicode/2754.png?v8",grimacing:"unicode/1f62c.png?v8",grin:"unicode/1f601.png?v8",grinning:"unicode/1f600.png?v8",guadeloupe:"unicode/1f1ec-1f1f5.png?v8",guam:"unicode/1f1ec-1f1fa.png?v8",guard:"unicode/1f482.png?v8",guardsman:"unicode/1f482-2642.png?v8",guardswoman:"unicode/1f482-2640.png?v8",guatemala:"unicode/1f1ec-1f1f9.png?v8",guernsey:"unicode/1f1ec-1f1ec.png?v8",guide_dog:"unicode/1f9ae.png?v8",guinea:"unicode/1f1ec-1f1f3.png?v8",guinea_bissau:"unicode/1f1ec-1f1fc.png?v8",guitar:"unicode/1f3b8.png?v8",gun:"unicode/1f52b.png?v8",guyana:"unicode/1f1ec-1f1fe.png?v8",haircut:"unicode/1f487.png?v8",haircut_man:"unicode/1f487-2642.png?v8",haircut_woman:"unicode/1f487-2640.png?v8",haiti:"unicode/1f1ed-1f1f9.png?v8",hamburger:"unicode/1f354.png?v8",hammer:"unicode/1f528.png?v8",hammer_and_pick:"unicode/2692.png?v8",hammer_and_wrench:"unicode/1f6e0.png?v8",hamster:"unicode/1f439.png?v8",hand:"unicode/270b.png?v8",hand_over_mouth:"unicode/1f92d.png?v8",handbag:"unicode/1f45c.png?v8",handball_person:"unicode/1f93e.png?v8",handshake:"unicode/1f91d.png?v8",hankey:"unicode/1f4a9.png?v8",hash:"unicode/0023-20e3.png?v8",hatched_chick:"unicode/1f425.png?v8",hatching_chick:"unicode/1f423.png?v8",headphones:"unicode/1f3a7.png?v8",headstone:"unicode/1faa6.png?v8",health_worker:"unicode/1f9d1-2695.png?v8",hear_no_evil:"unicode/1f649.png?v8",heard_mcdonald_islands:"unicode/1f1ed-1f1f2.png?v8",heart:"unicode/2764.png?v8",heart_decoration:"unicode/1f49f.png?v8",heart_eyes:"unicode/1f60d.png?v8",heart_eyes_cat:"unicode/1f63b.png?v8",heart_on_fire:"unicode/2764-1f525.png?v8",heartbeat:"unicode/1f493.png?v8",heartpulse:"unicode/1f497.png?v8",hearts:"unicode/2665.png?v8",heavy_check_mark:"unicode/2714.png?v8",heavy_division_sign:"unicode/2797.png?v8",heavy_dollar_sign:"unicode/1f4b2.png?v8",heavy_exclamation_mark:"unicode/2757.png?v8",heavy_heart_exclamation:"unicode/2763.png?v8",heavy_minus_sign:"unicode/2796.png?v8",heavy_multiplication_x:"unicode/2716.png?v8",heavy_plus_sign:"unicode/2795.png?v8",hedgehog:"unicode/1f994.png?v8",helicopter:"unicode/1f681.png?v8",herb:"unicode/1f33f.png?v8",hibiscus:"unicode/1f33a.png?v8",high_brightness:"unicode/1f506.png?v8",high_heel:"unicode/1f460.png?v8",hiking_boot:"unicode/1f97e.png?v8",hindu_temple:"unicode/1f6d5.png?v8",hippopotamus:"unicode/1f99b.png?v8",hocho:"unicode/1f52a.png?v8",hole:"unicode/1f573.png?v8",honduras:"unicode/1f1ed-1f1f3.png?v8",honey_pot:"unicode/1f36f.png?v8",honeybee:"unicode/1f41d.png?v8",hong_kong:"unicode/1f1ed-1f1f0.png?v8",hook:"unicode/1fa9d.png?v8",horse:"unicode/1f434.png?v8",horse_racing:"unicode/1f3c7.png?v8",hospital:"unicode/1f3e5.png?v8",hot_face:"unicode/1f975.png?v8",hot_pepper:"unicode/1f336.png?v8",hotdog:"unicode/1f32d.png?v8",hotel:"unicode/1f3e8.png?v8",hotsprings:"unicode/2668.png?v8",hourglass:"unicode/231b.png?v8",hourglass_flowing_sand:"unicode/23f3.png?v8",house:"unicode/1f3e0.png?v8",house_with_garden:"unicode/1f3e1.png?v8",houses:"unicode/1f3d8.png?v8",hugs:"unicode/1f917.png?v8",hungary:"unicode/1f1ed-1f1fa.png?v8",hurtrealbad:"hurtrealbad.png?v8",hushed:"unicode/1f62f.png?v8",hut:"unicode/1f6d6.png?v8",ice_cream:"unicode/1f368.png?v8",ice_cube:"unicode/1f9ca.png?v8",ice_hockey:"unicode/1f3d2.png?v8",ice_skate:"unicode/26f8.png?v8",icecream:"unicode/1f366.png?v8",iceland:"unicode/1f1ee-1f1f8.png?v8",id:"unicode/1f194.png?v8",ideograph_advantage:"unicode/1f250.png?v8",imp:"unicode/1f47f.png?v8",inbox_tray:"unicode/1f4e5.png?v8",incoming_envelope:"unicode/1f4e8.png?v8",india:"unicode/1f1ee-1f1f3.png?v8",indonesia:"unicode/1f1ee-1f1e9.png?v8",infinity:"unicode/267e.png?v8",information_desk_person:"unicode/1f481.png?v8",information_source:"unicode/2139.png?v8",innocent:"unicode/1f607.png?v8",interrobang:"unicode/2049.png?v8",iphone:"unicode/1f4f1.png?v8",iran:"unicode/1f1ee-1f1f7.png?v8",iraq:"unicode/1f1ee-1f1f6.png?v8",ireland:"unicode/1f1ee-1f1ea.png?v8",isle_of_man:"unicode/1f1ee-1f1f2.png?v8",israel:"unicode/1f1ee-1f1f1.png?v8",it:"unicode/1f1ee-1f1f9.png?v8",izakaya_lantern:"unicode/1f3ee.png?v8",jack_o_lantern:"unicode/1f383.png?v8",jamaica:"unicode/1f1ef-1f1f2.png?v8",japan:"unicode/1f5fe.png?v8",japanese_castle:"unicode/1f3ef.png?v8",japanese_goblin:"unicode/1f47a.png?v8",japanese_ogre:"unicode/1f479.png?v8",jeans:"unicode/1f456.png?v8",jersey:"unicode/1f1ef-1f1ea.png?v8",jigsaw:"unicode/1f9e9.png?v8",jordan:"unicode/1f1ef-1f1f4.png?v8",joy:"unicode/1f602.png?v8",joy_cat:"unicode/1f639.png?v8",joystick:"unicode/1f579.png?v8",jp:"unicode/1f1ef-1f1f5.png?v8",judge:"unicode/1f9d1-2696.png?v8",juggling_person:"unicode/1f939.png?v8",kaaba:"unicode/1f54b.png?v8",kangaroo:"unicode/1f998.png?v8",kazakhstan:"unicode/1f1f0-1f1ff.png?v8",kenya:"unicode/1f1f0-1f1ea.png?v8",key:"unicode/1f511.png?v8",keyboard:"unicode/2328.png?v8",keycap_ten:"unicode/1f51f.png?v8",kick_scooter:"unicode/1f6f4.png?v8",kimono:"unicode/1f458.png?v8",kiribati:"unicode/1f1f0-1f1ee.png?v8",kiss:"unicode/1f48b.png?v8",kissing:"unicode/1f617.png?v8",kissing_cat:"unicode/1f63d.png?v8",kissing_closed_eyes:"unicode/1f61a.png?v8",kissing_heart:"unicode/1f618.png?v8",kissing_smiling_eyes:"unicode/1f619.png?v8",kite:"unicode/1fa81.png?v8",kiwi_fruit:"unicode/1f95d.png?v8",kneeling_man:"unicode/1f9ce-2642.png?v8",kneeling_person:"unicode/1f9ce.png?v8",kneeling_woman:"unicode/1f9ce-2640.png?v8",knife:"unicode/1f52a.png?v8",knot:"unicode/1faa2.png?v8",koala:"unicode/1f428.png?v8",koko:"unicode/1f201.png?v8",kosovo:"unicode/1f1fd-1f1f0.png?v8",kr:"unicode/1f1f0-1f1f7.png?v8",kuwait:"unicode/1f1f0-1f1fc.png?v8",kyrgyzstan:"unicode/1f1f0-1f1ec.png?v8",lab_coat:"unicode/1f97c.png?v8",label:"unicode/1f3f7.png?v8",lacrosse:"unicode/1f94d.png?v8",ladder:"unicode/1fa9c.png?v8",lady_beetle:"unicode/1f41e.png?v8",lantern:"unicode/1f3ee.png?v8",laos:"unicode/1f1f1-1f1e6.png?v8",large_blue_circle:"unicode/1f535.png?v8",large_blue_diamond:"unicode/1f537.png?v8",large_orange_diamond:"unicode/1f536.png?v8",last_quarter_moon:"unicode/1f317.png?v8",last_quarter_moon_with_face:"unicode/1f31c.png?v8",latin_cross:"unicode/271d.png?v8",latvia:"unicode/1f1f1-1f1fb.png?v8",laughing:"unicode/1f606.png?v8",leafy_green:"unicode/1f96c.png?v8",leaves:"unicode/1f343.png?v8",lebanon:"unicode/1f1f1-1f1e7.png?v8",ledger:"unicode/1f4d2.png?v8",left_luggage:"unicode/1f6c5.png?v8",left_right_arrow:"unicode/2194.png?v8",left_speech_bubble:"unicode/1f5e8.png?v8",leftwards_arrow_with_hook:"unicode/21a9.png?v8",leg:"unicode/1f9b5.png?v8",lemon:"unicode/1f34b.png?v8",leo:"unicode/264c.png?v8",leopard:"unicode/1f406.png?v8",lesotho:"unicode/1f1f1-1f1f8.png?v8",level_slider:"unicode/1f39a.png?v8",liberia:"unicode/1f1f1-1f1f7.png?v8",libra:"unicode/264e.png?v8",libya:"unicode/1f1f1-1f1fe.png?v8",liechtenstein:"unicode/1f1f1-1f1ee.png?v8",light_rail:"unicode/1f688.png?v8",link:"unicode/1f517.png?v8",lion:"unicode/1f981.png?v8",lips:"unicode/1f444.png?v8",lipstick:"unicode/1f484.png?v8",lithuania:"unicode/1f1f1-1f1f9.png?v8",lizard:"unicode/1f98e.png?v8",llama:"unicode/1f999.png?v8",lobster:"unicode/1f99e.png?v8",lock:"unicode/1f512.png?v8",lock_with_ink_pen:"unicode/1f50f.png?v8",lollipop:"unicode/1f36d.png?v8",long_drum:"unicode/1fa98.png?v8",loop:"unicode/27bf.png?v8",lotion_bottle:"unicode/1f9f4.png?v8",lotus_position:"unicode/1f9d8.png?v8",lotus_position_man:"unicode/1f9d8-2642.png?v8",lotus_position_woman:"unicode/1f9d8-2640.png?v8",loud_sound:"unicode/1f50a.png?v8",loudspeaker:"unicode/1f4e2.png?v8",love_hotel:"unicode/1f3e9.png?v8",love_letter:"unicode/1f48c.png?v8",love_you_gesture:"unicode/1f91f.png?v8",low_brightness:"unicode/1f505.png?v8",luggage:"unicode/1f9f3.png?v8",lungs:"unicode/1fac1.png?v8",luxembourg:"unicode/1f1f1-1f1fa.png?v8",lying_face:"unicode/1f925.png?v8",m:"unicode/24c2.png?v8",macau:"unicode/1f1f2-1f1f4.png?v8",macedonia:"unicode/1f1f2-1f1f0.png?v8",madagascar:"unicode/1f1f2-1f1ec.png?v8",mag:"unicode/1f50d.png?v8",mag_right:"unicode/1f50e.png?v8",mage:"unicode/1f9d9.png?v8",mage_man:"unicode/1f9d9-2642.png?v8",mage_woman:"unicode/1f9d9-2640.png?v8",magic_wand:"unicode/1fa84.png?v8",magnet:"unicode/1f9f2.png?v8",mahjong:"unicode/1f004.png?v8",mailbox:"unicode/1f4eb.png?v8",mailbox_closed:"unicode/1f4ea.png?v8",mailbox_with_mail:"unicode/1f4ec.png?v8",mailbox_with_no_mail:"unicode/1f4ed.png?v8",malawi:"unicode/1f1f2-1f1fc.png?v8",malaysia:"unicode/1f1f2-1f1fe.png?v8",maldives:"unicode/1f1f2-1f1fb.png?v8",male_detective:"unicode/1f575-2642.png?v8",male_sign:"unicode/2642.png?v8",mali:"unicode/1f1f2-1f1f1.png?v8",malta:"unicode/1f1f2-1f1f9.png?v8",mammoth:"unicode/1f9a3.png?v8",man:"unicode/1f468.png?v8",man_artist:"unicode/1f468-1f3a8.png?v8",man_astronaut:"unicode/1f468-1f680.png?v8",man_beard:"unicode/1f9d4-2642.png?v8",man_cartwheeling:"unicode/1f938-2642.png?v8",man_cook:"unicode/1f468-1f373.png?v8",man_dancing:"unicode/1f57a.png?v8",man_facepalming:"unicode/1f926-2642.png?v8",man_factory_worker:"unicode/1f468-1f3ed.png?v8",man_farmer:"unicode/1f468-1f33e.png?v8",man_feeding_baby:"unicode/1f468-1f37c.png?v8",man_firefighter:"unicode/1f468-1f692.png?v8",man_health_worker:"unicode/1f468-2695.png?v8",man_in_manual_wheelchair:"unicode/1f468-1f9bd.png?v8",man_in_motorized_wheelchair:"unicode/1f468-1f9bc.png?v8",man_in_tuxedo:"unicode/1f935-2642.png?v8",man_judge:"unicode/1f468-2696.png?v8",man_juggling:"unicode/1f939-2642.png?v8",man_mechanic:"unicode/1f468-1f527.png?v8",man_office_worker:"unicode/1f468-1f4bc.png?v8",man_pilot:"unicode/1f468-2708.png?v8",man_playing_handball:"unicode/1f93e-2642.png?v8",man_playing_water_polo:"unicode/1f93d-2642.png?v8",man_scientist:"unicode/1f468-1f52c.png?v8",man_shrugging:"unicode/1f937-2642.png?v8",man_singer:"unicode/1f468-1f3a4.png?v8",man_student:"unicode/1f468-1f393.png?v8",man_teacher:"unicode/1f468-1f3eb.png?v8",man_technologist:"unicode/1f468-1f4bb.png?v8",man_with_gua_pi_mao:"unicode/1f472.png?v8",man_with_probing_cane:"unicode/1f468-1f9af.png?v8",man_with_turban:"unicode/1f473-2642.png?v8",man_with_veil:"unicode/1f470-2642.png?v8",mandarin:"unicode/1f34a.png?v8",mango:"unicode/1f96d.png?v8",mans_shoe:"unicode/1f45e.png?v8",mantelpiece_clock:"unicode/1f570.png?v8",manual_wheelchair:"unicode/1f9bd.png?v8",maple_leaf:"unicode/1f341.png?v8",marshall_islands:"unicode/1f1f2-1f1ed.png?v8",martial_arts_uniform:"unicode/1f94b.png?v8",martinique:"unicode/1f1f2-1f1f6.png?v8",mask:"unicode/1f637.png?v8",massage:"unicode/1f486.png?v8",massage_man:"unicode/1f486-2642.png?v8",massage_woman:"unicode/1f486-2640.png?v8",mate:"unicode/1f9c9.png?v8",mauritania:"unicode/1f1f2-1f1f7.png?v8",mauritius:"unicode/1f1f2-1f1fa.png?v8",mayotte:"unicode/1f1fe-1f1f9.png?v8",meat_on_bone:"unicode/1f356.png?v8",mechanic:"unicode/1f9d1-1f527.png?v8",mechanical_arm:"unicode/1f9be.png?v8",mechanical_leg:"unicode/1f9bf.png?v8",medal_military:"unicode/1f396.png?v8",medal_sports:"unicode/1f3c5.png?v8",medical_symbol:"unicode/2695.png?v8",mega:"unicode/1f4e3.png?v8",melon:"unicode/1f348.png?v8",memo:"unicode/1f4dd.png?v8",men_wrestling:"unicode/1f93c-2642.png?v8",mending_heart:"unicode/2764-1fa79.png?v8",menorah:"unicode/1f54e.png?v8",mens:"unicode/1f6b9.png?v8",mermaid:"unicode/1f9dc-2640.png?v8",merman:"unicode/1f9dc-2642.png?v8",merperson:"unicode/1f9dc.png?v8",metal:"unicode/1f918.png?v8",metro:"unicode/1f687.png?v8",mexico:"unicode/1f1f2-1f1fd.png?v8",microbe:"unicode/1f9a0.png?v8",micronesia:"unicode/1f1eb-1f1f2.png?v8",microphone:"unicode/1f3a4.png?v8",microscope:"unicode/1f52c.png?v8",middle_finger:"unicode/1f595.png?v8",military_helmet:"unicode/1fa96.png?v8",milk_glass:"unicode/1f95b.png?v8",milky_way:"unicode/1f30c.png?v8",minibus:"unicode/1f690.png?v8",minidisc:"unicode/1f4bd.png?v8",mirror:"unicode/1fa9e.png?v8",mobile_phone_off:"unicode/1f4f4.png?v8",moldova:"unicode/1f1f2-1f1e9.png?v8",monaco:"unicode/1f1f2-1f1e8.png?v8",money_mouth_face:"unicode/1f911.png?v8",money_with_wings:"unicode/1f4b8.png?v8",moneybag:"unicode/1f4b0.png?v8",mongolia:"unicode/1f1f2-1f1f3.png?v8",monkey:"unicode/1f412.png?v8",monkey_face:"unicode/1f435.png?v8",monocle_face:"unicode/1f9d0.png?v8",monorail:"unicode/1f69d.png?v8",montenegro:"unicode/1f1f2-1f1ea.png?v8",montserrat:"unicode/1f1f2-1f1f8.png?v8",moon:"unicode/1f314.png?v8",moon_cake:"unicode/1f96e.png?v8",morocco:"unicode/1f1f2-1f1e6.png?v8",mortar_board:"unicode/1f393.png?v8",mosque:"unicode/1f54c.png?v8",mosquito:"unicode/1f99f.png?v8",motor_boat:"unicode/1f6e5.png?v8",motor_scooter:"unicode/1f6f5.png?v8",motorcycle:"unicode/1f3cd.png?v8",motorized_wheelchair:"unicode/1f9bc.png?v8",motorway:"unicode/1f6e3.png?v8",mount_fuji:"unicode/1f5fb.png?v8",mountain:"unicode/26f0.png?v8",mountain_bicyclist:"unicode/1f6b5.png?v8",mountain_biking_man:"unicode/1f6b5-2642.png?v8",mountain_biking_woman:"unicode/1f6b5-2640.png?v8",mountain_cableway:"unicode/1f6a0.png?v8",mountain_railway:"unicode/1f69e.png?v8",mountain_snow:"unicode/1f3d4.png?v8",mouse:"unicode/1f42d.png?v8",mouse2:"unicode/1f401.png?v8",mouse_trap:"unicode/1faa4.png?v8",movie_camera:"unicode/1f3a5.png?v8",moyai:"unicode/1f5ff.png?v8",mozambique:"unicode/1f1f2-1f1ff.png?v8",mrs_claus:"unicode/1f936.png?v8",muscle:"unicode/1f4aa.png?v8",mushroom:"unicode/1f344.png?v8",musical_keyboard:"unicode/1f3b9.png?v8",musical_note:"unicode/1f3b5.png?v8",musical_score:"unicode/1f3bc.png?v8",mute:"unicode/1f507.png?v8",mx_claus:"unicode/1f9d1-1f384.png?v8",myanmar:"unicode/1f1f2-1f1f2.png?v8",nail_care:"unicode/1f485.png?v8",name_badge:"unicode/1f4db.png?v8",namibia:"unicode/1f1f3-1f1e6.png?v8",national_park:"unicode/1f3de.png?v8",nauru:"unicode/1f1f3-1f1f7.png?v8",nauseated_face:"unicode/1f922.png?v8",nazar_amulet:"unicode/1f9ff.png?v8",neckbeard:"neckbeard.png?v8",necktie:"unicode/1f454.png?v8",negative_squared_cross_mark:"unicode/274e.png?v8",nepal:"unicode/1f1f3-1f1f5.png?v8",nerd_face:"unicode/1f913.png?v8",nesting_dolls:"unicode/1fa86.png?v8",netherlands:"unicode/1f1f3-1f1f1.png?v8",neutral_face:"unicode/1f610.png?v8",new:"unicode/1f195.png?v8",new_caledonia:"unicode/1f1f3-1f1e8.png?v8",new_moon:"unicode/1f311.png?v8",new_moon_with_face:"unicode/1f31a.png?v8",new_zealand:"unicode/1f1f3-1f1ff.png?v8",newspaper:"unicode/1f4f0.png?v8",newspaper_roll:"unicode/1f5de.png?v8",next_track_button:"unicode/23ed.png?v8",ng:"unicode/1f196.png?v8",ng_man:"unicode/1f645-2642.png?v8",ng_woman:"unicode/1f645-2640.png?v8",nicaragua:"unicode/1f1f3-1f1ee.png?v8",niger:"unicode/1f1f3-1f1ea.png?v8",nigeria:"unicode/1f1f3-1f1ec.png?v8",night_with_stars:"unicode/1f303.png?v8",nine:"unicode/0039-20e3.png?v8",ninja:"unicode/1f977.png?v8",niue:"unicode/1f1f3-1f1fa.png?v8",no_bell:"unicode/1f515.png?v8",no_bicycles:"unicode/1f6b3.png?v8",no_entry:"unicode/26d4.png?v8",no_entry_sign:"unicode/1f6ab.png?v8",no_good:"unicode/1f645.png?v8",no_good_man:"unicode/1f645-2642.png?v8",no_good_woman:"unicode/1f645-2640.png?v8",no_mobile_phones:"unicode/1f4f5.png?v8",no_mouth:"unicode/1f636.png?v8",no_pedestrians:"unicode/1f6b7.png?v8",no_smoking:"unicode/1f6ad.png?v8","non-potable_water":"unicode/1f6b1.png?v8",norfolk_island:"unicode/1f1f3-1f1eb.png?v8",north_korea:"unicode/1f1f0-1f1f5.png?v8",northern_mariana_islands:"unicode/1f1f2-1f1f5.png?v8",norway:"unicode/1f1f3-1f1f4.png?v8",nose:"unicode/1f443.png?v8",notebook:"unicode/1f4d3.png?v8",notebook_with_decorative_cover:"unicode/1f4d4.png?v8",notes:"unicode/1f3b6.png?v8",nut_and_bolt:"unicode/1f529.png?v8",o:"unicode/2b55.png?v8",o2:"unicode/1f17e.png?v8",ocean:"unicode/1f30a.png?v8",octocat:"octocat.png?v8",octopus:"unicode/1f419.png?v8",oden:"unicode/1f362.png?v8",office:"unicode/1f3e2.png?v8",office_worker:"unicode/1f9d1-1f4bc.png?v8",oil_drum:"unicode/1f6e2.png?v8",ok:"unicode/1f197.png?v8",ok_hand:"unicode/1f44c.png?v8",ok_man:"unicode/1f646-2642.png?v8",ok_person:"unicode/1f646.png?v8",ok_woman:"unicode/1f646-2640.png?v8",old_key:"unicode/1f5dd.png?v8",older_adult:"unicode/1f9d3.png?v8",older_man:"unicode/1f474.png?v8",older_woman:"unicode/1f475.png?v8",olive:"unicode/1fad2.png?v8",om:"unicode/1f549.png?v8",oman:"unicode/1f1f4-1f1f2.png?v8",on:"unicode/1f51b.png?v8",oncoming_automobile:"unicode/1f698.png?v8",oncoming_bus:"unicode/1f68d.png?v8",oncoming_police_car:"unicode/1f694.png?v8",oncoming_taxi:"unicode/1f696.png?v8",one:"unicode/0031-20e3.png?v8",one_piece_swimsuit:"unicode/1fa71.png?v8",onion:"unicode/1f9c5.png?v8",open_book:"unicode/1f4d6.png?v8",open_file_folder:"unicode/1f4c2.png?v8",open_hands:"unicode/1f450.png?v8",open_mouth:"unicode/1f62e.png?v8",open_umbrella:"unicode/2602.png?v8",ophiuchus:"unicode/26ce.png?v8",orange:"unicode/1f34a.png?v8",orange_book:"unicode/1f4d9.png?v8",orange_circle:"unicode/1f7e0.png?v8",orange_heart:"unicode/1f9e1.png?v8",orange_square:"unicode/1f7e7.png?v8",orangutan:"unicode/1f9a7.png?v8",orthodox_cross:"unicode/2626.png?v8",otter:"unicode/1f9a6.png?v8",outbox_tray:"unicode/1f4e4.png?v8",owl:"unicode/1f989.png?v8",ox:"unicode/1f402.png?v8",oyster:"unicode/1f9aa.png?v8",package:"unicode/1f4e6.png?v8",page_facing_up:"unicode/1f4c4.png?v8",page_with_curl:"unicode/1f4c3.png?v8",pager:"unicode/1f4df.png?v8",paintbrush:"unicode/1f58c.png?v8",pakistan:"unicode/1f1f5-1f1f0.png?v8",palau:"unicode/1f1f5-1f1fc.png?v8",palestinian_territories:"unicode/1f1f5-1f1f8.png?v8",palm_tree:"unicode/1f334.png?v8",palms_up_together:"unicode/1f932.png?v8",panama:"unicode/1f1f5-1f1e6.png?v8",pancakes:"unicode/1f95e.png?v8",panda_face:"unicode/1f43c.png?v8",paperclip:"unicode/1f4ce.png?v8",paperclips:"unicode/1f587.png?v8",papua_new_guinea:"unicode/1f1f5-1f1ec.png?v8",parachute:"unicode/1fa82.png?v8",paraguay:"unicode/1f1f5-1f1fe.png?v8",parasol_on_ground:"unicode/26f1.png?v8",parking:"unicode/1f17f.png?v8",parrot:"unicode/1f99c.png?v8",part_alternation_mark:"unicode/303d.png?v8",partly_sunny:"unicode/26c5.png?v8",partying_face:"unicode/1f973.png?v8",passenger_ship:"unicode/1f6f3.png?v8",passport_control:"unicode/1f6c2.png?v8",pause_button:"unicode/23f8.png?v8",paw_prints:"unicode/1f43e.png?v8",peace_symbol:"unicode/262e.png?v8",peach:"unicode/1f351.png?v8",peacock:"unicode/1f99a.png?v8",peanuts:"unicode/1f95c.png?v8",pear:"unicode/1f350.png?v8",pen:"unicode/1f58a.png?v8",pencil:"unicode/1f4dd.png?v8",pencil2:"unicode/270f.png?v8",penguin:"unicode/1f427.png?v8",pensive:"unicode/1f614.png?v8",people_holding_hands:"unicode/1f9d1-1f91d-1f9d1.png?v8",people_hugging:"unicode/1fac2.png?v8",performing_arts:"unicode/1f3ad.png?v8",persevere:"unicode/1f623.png?v8",person_bald:"unicode/1f9d1-1f9b2.png?v8",person_curly_hair:"unicode/1f9d1-1f9b1.png?v8",person_feeding_baby:"unicode/1f9d1-1f37c.png?v8",person_fencing:"unicode/1f93a.png?v8",person_in_manual_wheelchair:"unicode/1f9d1-1f9bd.png?v8",person_in_motorized_wheelchair:"unicode/1f9d1-1f9bc.png?v8",person_in_tuxedo:"unicode/1f935.png?v8",person_red_hair:"unicode/1f9d1-1f9b0.png?v8",person_white_hair:"unicode/1f9d1-1f9b3.png?v8",person_with_probing_cane:"unicode/1f9d1-1f9af.png?v8",person_with_turban:"unicode/1f473.png?v8",person_with_veil:"unicode/1f470.png?v8",peru:"unicode/1f1f5-1f1ea.png?v8",petri_dish:"unicode/1f9eb.png?v8",philippines:"unicode/1f1f5-1f1ed.png?v8",phone:"unicode/260e.png?v8",pick:"unicode/26cf.png?v8",pickup_truck:"unicode/1f6fb.png?v8",pie:"unicode/1f967.png?v8",pig:"unicode/1f437.png?v8",pig2:"unicode/1f416.png?v8",pig_nose:"unicode/1f43d.png?v8",pill:"unicode/1f48a.png?v8",pilot:"unicode/1f9d1-2708.png?v8",pinata:"unicode/1fa85.png?v8",pinched_fingers:"unicode/1f90c.png?v8",pinching_hand:"unicode/1f90f.png?v8",pineapple:"unicode/1f34d.png?v8",ping_pong:"unicode/1f3d3.png?v8",pirate_flag:"unicode/1f3f4-2620.png?v8",pisces:"unicode/2653.png?v8",pitcairn_islands:"unicode/1f1f5-1f1f3.png?v8",pizza:"unicode/1f355.png?v8",placard:"unicode/1faa7.png?v8",place_of_worship:"unicode/1f6d0.png?v8",plate_with_cutlery:"unicode/1f37d.png?v8",play_or_pause_button:"unicode/23ef.png?v8",pleading_face:"unicode/1f97a.png?v8",plunger:"unicode/1faa0.png?v8",point_down:"unicode/1f447.png?v8",point_left:"unicode/1f448.png?v8",point_right:"unicode/1f449.png?v8",point_up:"unicode/261d.png?v8",point_up_2:"unicode/1f446.png?v8",poland:"unicode/1f1f5-1f1f1.png?v8",polar_bear:"unicode/1f43b-2744.png?v8",police_car:"unicode/1f693.png?v8",police_officer:"unicode/1f46e.png?v8",policeman:"unicode/1f46e-2642.png?v8",policewoman:"unicode/1f46e-2640.png?v8",poodle:"unicode/1f429.png?v8",poop:"unicode/1f4a9.png?v8",popcorn:"unicode/1f37f.png?v8",portugal:"unicode/1f1f5-1f1f9.png?v8",post_office:"unicode/1f3e3.png?v8",postal_horn:"unicode/1f4ef.png?v8",postbox:"unicode/1f4ee.png?v8",potable_water:"unicode/1f6b0.png?v8",potato:"unicode/1f954.png?v8",potted_plant:"unicode/1fab4.png?v8",pouch:"unicode/1f45d.png?v8",poultry_leg:"unicode/1f357.png?v8",pound:"unicode/1f4b7.png?v8",pout:"unicode/1f621.png?v8",pouting_cat:"unicode/1f63e.png?v8",pouting_face:"unicode/1f64e.png?v8",pouting_man:"unicode/1f64e-2642.png?v8",pouting_woman:"unicode/1f64e-2640.png?v8",pray:"unicode/1f64f.png?v8",prayer_beads:"unicode/1f4ff.png?v8",pregnant_woman:"unicode/1f930.png?v8",pretzel:"unicode/1f968.png?v8",previous_track_button:"unicode/23ee.png?v8",prince:"unicode/1f934.png?v8",princess:"unicode/1f478.png?v8",printer:"unicode/1f5a8.png?v8",probing_cane:"unicode/1f9af.png?v8",puerto_rico:"unicode/1f1f5-1f1f7.png?v8",punch:"unicode/1f44a.png?v8",purple_circle:"unicode/1f7e3.png?v8",purple_heart:"unicode/1f49c.png?v8",purple_square:"unicode/1f7ea.png?v8",purse:"unicode/1f45b.png?v8",pushpin:"unicode/1f4cc.png?v8",put_litter_in_its_place:"unicode/1f6ae.png?v8",qatar:"unicode/1f1f6-1f1e6.png?v8",question:"unicode/2753.png?v8",rabbit:"unicode/1f430.png?v8",rabbit2:"unicode/1f407.png?v8",raccoon:"unicode/1f99d.png?v8",racehorse:"unicode/1f40e.png?v8",racing_car:"unicode/1f3ce.png?v8",radio:"unicode/1f4fb.png?v8",radio_button:"unicode/1f518.png?v8",radioactive:"unicode/2622.png?v8",rage:"unicode/1f621.png?v8",rage1:"rage1.png?v8",rage2:"rage2.png?v8",rage3:"rage3.png?v8",rage4:"rage4.png?v8",railway_car:"unicode/1f683.png?v8",railway_track:"unicode/1f6e4.png?v8",rainbow:"unicode/1f308.png?v8",rainbow_flag:"unicode/1f3f3-1f308.png?v8",raised_back_of_hand:"unicode/1f91a.png?v8",raised_eyebrow:"unicode/1f928.png?v8",raised_hand:"unicode/270b.png?v8",raised_hand_with_fingers_splayed:"unicode/1f590.png?v8",raised_hands:"unicode/1f64c.png?v8",raising_hand:"unicode/1f64b.png?v8",raising_hand_man:"unicode/1f64b-2642.png?v8",raising_hand_woman:"unicode/1f64b-2640.png?v8",ram:"unicode/1f40f.png?v8",ramen:"unicode/1f35c.png?v8",rat:"unicode/1f400.png?v8",razor:"unicode/1fa92.png?v8",receipt:"unicode/1f9fe.png?v8",record_button:"unicode/23fa.png?v8",recycle:"unicode/267b.png?v8",red_car:"unicode/1f697.png?v8",red_circle:"unicode/1f534.png?v8",red_envelope:"unicode/1f9e7.png?v8",red_haired_man:"unicode/1f468-1f9b0.png?v8",red_haired_woman:"unicode/1f469-1f9b0.png?v8",red_square:"unicode/1f7e5.png?v8",registered:"unicode/00ae.png?v8",relaxed:"unicode/263a.png?v8",relieved:"unicode/1f60c.png?v8",reminder_ribbon:"unicode/1f397.png?v8",repeat:"unicode/1f501.png?v8",repeat_one:"unicode/1f502.png?v8",rescue_worker_helmet:"unicode/26d1.png?v8",restroom:"unicode/1f6bb.png?v8",reunion:"unicode/1f1f7-1f1ea.png?v8",revolving_hearts:"unicode/1f49e.png?v8",rewind:"unicode/23ea.png?v8",rhinoceros:"unicode/1f98f.png?v8",ribbon:"unicode/1f380.png?v8",rice:"unicode/1f35a.png?v8",rice_ball:"unicode/1f359.png?v8",rice_cracker:"unicode/1f358.png?v8",rice_scene:"unicode/1f391.png?v8",right_anger_bubble:"unicode/1f5ef.png?v8",ring:"unicode/1f48d.png?v8",ringed_planet:"unicode/1fa90.png?v8",robot:"unicode/1f916.png?v8",rock:"unicode/1faa8.png?v8",rocket:"unicode/1f680.png?v8",rofl:"unicode/1f923.png?v8",roll_eyes:"unicode/1f644.png?v8",roll_of_paper:"unicode/1f9fb.png?v8",roller_coaster:"unicode/1f3a2.png?v8",roller_skate:"unicode/1f6fc.png?v8",romania:"unicode/1f1f7-1f1f4.png?v8",rooster:"unicode/1f413.png?v8",rose:"unicode/1f339.png?v8",rosette:"unicode/1f3f5.png?v8",rotating_light:"unicode/1f6a8.png?v8",round_pushpin:"unicode/1f4cd.png?v8",rowboat:"unicode/1f6a3.png?v8",rowing_man:"unicode/1f6a3-2642.png?v8",rowing_woman:"unicode/1f6a3-2640.png?v8",ru:"unicode/1f1f7-1f1fa.png?v8",rugby_football:"unicode/1f3c9.png?v8",runner:"unicode/1f3c3.png?v8",running:"unicode/1f3c3.png?v8",running_man:"unicode/1f3c3-2642.png?v8",running_shirt_with_sash:"unicode/1f3bd.png?v8",running_woman:"unicode/1f3c3-2640.png?v8",rwanda:"unicode/1f1f7-1f1fc.png?v8",sa:"unicode/1f202.png?v8",safety_pin:"unicode/1f9f7.png?v8",safety_vest:"unicode/1f9ba.png?v8",sagittarius:"unicode/2650.png?v8",sailboat:"unicode/26f5.png?v8",sake:"unicode/1f376.png?v8",salt:"unicode/1f9c2.png?v8",samoa:"unicode/1f1fc-1f1f8.png?v8",san_marino:"unicode/1f1f8-1f1f2.png?v8",sandal:"unicode/1f461.png?v8",sandwich:"unicode/1f96a.png?v8",santa:"unicode/1f385.png?v8",sao_tome_principe:"unicode/1f1f8-1f1f9.png?v8",sari:"unicode/1f97b.png?v8",sassy_man:"unicode/1f481-2642.png?v8",sassy_woman:"unicode/1f481-2640.png?v8",satellite:"unicode/1f4e1.png?v8",satisfied:"unicode/1f606.png?v8",saudi_arabia:"unicode/1f1f8-1f1e6.png?v8",sauna_man:"unicode/1f9d6-2642.png?v8",sauna_person:"unicode/1f9d6.png?v8",sauna_woman:"unicode/1f9d6-2640.png?v8",sauropod:"unicode/1f995.png?v8",saxophone:"unicode/1f3b7.png?v8",scarf:"unicode/1f9e3.png?v8",school:"unicode/1f3eb.png?v8",school_satchel:"unicode/1f392.png?v8",scientist:"unicode/1f9d1-1f52c.png?v8",scissors:"unicode/2702.png?v8",scorpion:"unicode/1f982.png?v8",scorpius:"unicode/264f.png?v8",scotland:"unicode/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png?v8",scream:"unicode/1f631.png?v8",scream_cat:"unicode/1f640.png?v8",screwdriver:"unicode/1fa9b.png?v8",scroll:"unicode/1f4dc.png?v8",seal:"unicode/1f9ad.png?v8",seat:"unicode/1f4ba.png?v8",secret:"unicode/3299.png?v8",see_no_evil:"unicode/1f648.png?v8",seedling:"unicode/1f331.png?v8",selfie:"unicode/1f933.png?v8",senegal:"unicode/1f1f8-1f1f3.png?v8",serbia:"unicode/1f1f7-1f1f8.png?v8",service_dog:"unicode/1f415-1f9ba.png?v8",seven:"unicode/0037-20e3.png?v8",sewing_needle:"unicode/1faa1.png?v8",seychelles:"unicode/1f1f8-1f1e8.png?v8",shallow_pan_of_food:"unicode/1f958.png?v8",shamrock:"unicode/2618.png?v8",shark:"unicode/1f988.png?v8",shaved_ice:"unicode/1f367.png?v8",sheep:"unicode/1f411.png?v8",shell:"unicode/1f41a.png?v8",shield:"unicode/1f6e1.png?v8",shinto_shrine:"unicode/26e9.png?v8",ship:"unicode/1f6a2.png?v8",shipit:"shipit.png?v8",shirt:"unicode/1f455.png?v8",shit:"unicode/1f4a9.png?v8",shoe:"unicode/1f45e.png?v8",shopping:"unicode/1f6cd.png?v8",shopping_cart:"unicode/1f6d2.png?v8",shorts:"unicode/1fa73.png?v8",shower:"unicode/1f6bf.png?v8",shrimp:"unicode/1f990.png?v8",shrug:"unicode/1f937.png?v8",shushing_face:"unicode/1f92b.png?v8",sierra_leone:"unicode/1f1f8-1f1f1.png?v8",signal_strength:"unicode/1f4f6.png?v8",singapore:"unicode/1f1f8-1f1ec.png?v8",singer:"unicode/1f9d1-1f3a4.png?v8",sint_maarten:"unicode/1f1f8-1f1fd.png?v8",six:"unicode/0036-20e3.png?v8",six_pointed_star:"unicode/1f52f.png?v8",skateboard:"unicode/1f6f9.png?v8",ski:"unicode/1f3bf.png?v8",skier:"unicode/26f7.png?v8",skull:"unicode/1f480.png?v8",skull_and_crossbones:"unicode/2620.png?v8",skunk:"unicode/1f9a8.png?v8",sled:"unicode/1f6f7.png?v8",sleeping:"unicode/1f634.png?v8",sleeping_bed:"unicode/1f6cc.png?v8",sleepy:"unicode/1f62a.png?v8",slightly_frowning_face:"unicode/1f641.png?v8",slightly_smiling_face:"unicode/1f642.png?v8",slot_machine:"unicode/1f3b0.png?v8",sloth:"unicode/1f9a5.png?v8",slovakia:"unicode/1f1f8-1f1f0.png?v8",slovenia:"unicode/1f1f8-1f1ee.png?v8",small_airplane:"unicode/1f6e9.png?v8",small_blue_diamond:"unicode/1f539.png?v8",small_orange_diamond:"unicode/1f538.png?v8",small_red_triangle:"unicode/1f53a.png?v8",small_red_triangle_down:"unicode/1f53b.png?v8",smile:"unicode/1f604.png?v8",smile_cat:"unicode/1f638.png?v8",smiley:"unicode/1f603.png?v8",smiley_cat:"unicode/1f63a.png?v8",smiling_face_with_tear:"unicode/1f972.png?v8",smiling_face_with_three_hearts:"unicode/1f970.png?v8",smiling_imp:"unicode/1f608.png?v8",smirk:"unicode/1f60f.png?v8",smirk_cat:"unicode/1f63c.png?v8",smoking:"unicode/1f6ac.png?v8",snail:"unicode/1f40c.png?v8",snake:"unicode/1f40d.png?v8",sneezing_face:"unicode/1f927.png?v8",snowboarder:"unicode/1f3c2.png?v8",snowflake:"unicode/2744.png?v8",snowman:"unicode/26c4.png?v8",snowman_with_snow:"unicode/2603.png?v8",soap:"unicode/1f9fc.png?v8",sob:"unicode/1f62d.png?v8",soccer:"unicode/26bd.png?v8",socks:"unicode/1f9e6.png?v8",softball:"unicode/1f94e.png?v8",solomon_islands:"unicode/1f1f8-1f1e7.png?v8",somalia:"unicode/1f1f8-1f1f4.png?v8",soon:"unicode/1f51c.png?v8",sos:"unicode/1f198.png?v8",sound:"unicode/1f509.png?v8",south_africa:"unicode/1f1ff-1f1e6.png?v8",south_georgia_south_sandwich_islands:"unicode/1f1ec-1f1f8.png?v8",south_sudan:"unicode/1f1f8-1f1f8.png?v8",space_invader:"unicode/1f47e.png?v8",spades:"unicode/2660.png?v8",spaghetti:"unicode/1f35d.png?v8",sparkle:"unicode/2747.png?v8",sparkler:"unicode/1f387.png?v8",sparkles:"unicode/2728.png?v8",sparkling_heart:"unicode/1f496.png?v8",speak_no_evil:"unicode/1f64a.png?v8",speaker:"unicode/1f508.png?v8",speaking_head:"unicode/1f5e3.png?v8",speech_balloon:"unicode/1f4ac.png?v8",speedboat:"unicode/1f6a4.png?v8",spider:"unicode/1f577.png?v8",spider_web:"unicode/1f578.png?v8",spiral_calendar:"unicode/1f5d3.png?v8",spiral_notepad:"unicode/1f5d2.png?v8",sponge:"unicode/1f9fd.png?v8",spoon:"unicode/1f944.png?v8",squid:"unicode/1f991.png?v8",sri_lanka:"unicode/1f1f1-1f1f0.png?v8",st_barthelemy:"unicode/1f1e7-1f1f1.png?v8",st_helena:"unicode/1f1f8-1f1ed.png?v8",st_kitts_nevis:"unicode/1f1f0-1f1f3.png?v8",st_lucia:"unicode/1f1f1-1f1e8.png?v8",st_martin:"unicode/1f1f2-1f1eb.png?v8",st_pierre_miquelon:"unicode/1f1f5-1f1f2.png?v8",st_vincent_grenadines:"unicode/1f1fb-1f1e8.png?v8",stadium:"unicode/1f3df.png?v8",standing_man:"unicode/1f9cd-2642.png?v8",standing_person:"unicode/1f9cd.png?v8",standing_woman:"unicode/1f9cd-2640.png?v8",star:"unicode/2b50.png?v8",star2:"unicode/1f31f.png?v8",star_and_crescent:"unicode/262a.png?v8",star_of_david:"unicode/2721.png?v8",star_struck:"unicode/1f929.png?v8",stars:"unicode/1f320.png?v8",station:"unicode/1f689.png?v8",statue_of_liberty:"unicode/1f5fd.png?v8",steam_locomotive:"unicode/1f682.png?v8",stethoscope:"unicode/1fa7a.png?v8",stew:"unicode/1f372.png?v8",stop_button:"unicode/23f9.png?v8",stop_sign:"unicode/1f6d1.png?v8",stopwatch:"unicode/23f1.png?v8",straight_ruler:"unicode/1f4cf.png?v8",strawberry:"unicode/1f353.png?v8",stuck_out_tongue:"unicode/1f61b.png?v8",stuck_out_tongue_closed_eyes:"unicode/1f61d.png?v8",stuck_out_tongue_winking_eye:"unicode/1f61c.png?v8",student:"unicode/1f9d1-1f393.png?v8",studio_microphone:"unicode/1f399.png?v8",stuffed_flatbread:"unicode/1f959.png?v8",sudan:"unicode/1f1f8-1f1e9.png?v8",sun_behind_large_cloud:"unicode/1f325.png?v8",sun_behind_rain_cloud:"unicode/1f326.png?v8",sun_behind_small_cloud:"unicode/1f324.png?v8",sun_with_face:"unicode/1f31e.png?v8",sunflower:"unicode/1f33b.png?v8",sunglasses:"unicode/1f60e.png?v8",sunny:"unicode/2600.png?v8",sunrise:"unicode/1f305.png?v8",sunrise_over_mountains:"unicode/1f304.png?v8",superhero:"unicode/1f9b8.png?v8",superhero_man:"unicode/1f9b8-2642.png?v8",superhero_woman:"unicode/1f9b8-2640.png?v8",supervillain:"unicode/1f9b9.png?v8",supervillain_man:"unicode/1f9b9-2642.png?v8",supervillain_woman:"unicode/1f9b9-2640.png?v8",surfer:"unicode/1f3c4.png?v8",surfing_man:"unicode/1f3c4-2642.png?v8",surfing_woman:"unicode/1f3c4-2640.png?v8",suriname:"unicode/1f1f8-1f1f7.png?v8",sushi:"unicode/1f363.png?v8",suspect:"suspect.png?v8",suspension_railway:"unicode/1f69f.png?v8",svalbard_jan_mayen:"unicode/1f1f8-1f1ef.png?v8",swan:"unicode/1f9a2.png?v8",swaziland:"unicode/1f1f8-1f1ff.png?v8",sweat:"unicode/1f613.png?v8",sweat_drops:"unicode/1f4a6.png?v8",sweat_smile:"unicode/1f605.png?v8",sweden:"unicode/1f1f8-1f1ea.png?v8",sweet_potato:"unicode/1f360.png?v8",swim_brief:"unicode/1fa72.png?v8",swimmer:"unicode/1f3ca.png?v8",swimming_man:"unicode/1f3ca-2642.png?v8",swimming_woman:"unicode/1f3ca-2640.png?v8",switzerland:"unicode/1f1e8-1f1ed.png?v8",symbols:"unicode/1f523.png?v8",synagogue:"unicode/1f54d.png?v8",syria:"unicode/1f1f8-1f1fe.png?v8",syringe:"unicode/1f489.png?v8","t-rex":"unicode/1f996.png?v8",taco:"unicode/1f32e.png?v8",tada:"unicode/1f389.png?v8",taiwan:"unicode/1f1f9-1f1fc.png?v8",tajikistan:"unicode/1f1f9-1f1ef.png?v8",takeout_box:"unicode/1f961.png?v8",tamale:"unicode/1fad4.png?v8",tanabata_tree:"unicode/1f38b.png?v8",tangerine:"unicode/1f34a.png?v8",tanzania:"unicode/1f1f9-1f1ff.png?v8",taurus:"unicode/2649.png?v8",taxi:"unicode/1f695.png?v8",tea:"unicode/1f375.png?v8",teacher:"unicode/1f9d1-1f3eb.png?v8",teapot:"unicode/1fad6.png?v8",technologist:"unicode/1f9d1-1f4bb.png?v8",teddy_bear:"unicode/1f9f8.png?v8",telephone:"unicode/260e.png?v8",telephone_receiver:"unicode/1f4de.png?v8",telescope:"unicode/1f52d.png?v8",tennis:"unicode/1f3be.png?v8",tent:"unicode/26fa.png?v8",test_tube:"unicode/1f9ea.png?v8",thailand:"unicode/1f1f9-1f1ed.png?v8",thermometer:"unicode/1f321.png?v8",thinking:"unicode/1f914.png?v8",thong_sandal:"unicode/1fa74.png?v8",thought_balloon:"unicode/1f4ad.png?v8",thread:"unicode/1f9f5.png?v8",three:"unicode/0033-20e3.png?v8",thumbsdown:"unicode/1f44e.png?v8",thumbsup:"unicode/1f44d.png?v8",ticket:"unicode/1f3ab.png?v8",tickets:"unicode/1f39f.png?v8",tiger:"unicode/1f42f.png?v8",tiger2:"unicode/1f405.png?v8",timer_clock:"unicode/23f2.png?v8",timor_leste:"unicode/1f1f9-1f1f1.png?v8",tipping_hand_man:"unicode/1f481-2642.png?v8",tipping_hand_person:"unicode/1f481.png?v8",tipping_hand_woman:"unicode/1f481-2640.png?v8",tired_face:"unicode/1f62b.png?v8",tm:"unicode/2122.png?v8",togo:"unicode/1f1f9-1f1ec.png?v8",toilet:"unicode/1f6bd.png?v8",tokelau:"unicode/1f1f9-1f1f0.png?v8",tokyo_tower:"unicode/1f5fc.png?v8",tomato:"unicode/1f345.png?v8",tonga:"unicode/1f1f9-1f1f4.png?v8",tongue:"unicode/1f445.png?v8",toolbox:"unicode/1f9f0.png?v8",tooth:"unicode/1f9b7.png?v8",toothbrush:"unicode/1faa5.png?v8",top:"unicode/1f51d.png?v8",tophat:"unicode/1f3a9.png?v8",tornado:"unicode/1f32a.png?v8",tr:"unicode/1f1f9-1f1f7.png?v8",trackball:"unicode/1f5b2.png?v8",tractor:"unicode/1f69c.png?v8",traffic_light:"unicode/1f6a5.png?v8",train:"unicode/1f68b.png?v8",train2:"unicode/1f686.png?v8",tram:"unicode/1f68a.png?v8",transgender_flag:"unicode/1f3f3-26a7.png?v8",transgender_symbol:"unicode/26a7.png?v8",triangular_flag_on_post:"unicode/1f6a9.png?v8",triangular_ruler:"unicode/1f4d0.png?v8",trident:"unicode/1f531.png?v8",trinidad_tobago:"unicode/1f1f9-1f1f9.png?v8",tristan_da_cunha:"unicode/1f1f9-1f1e6.png?v8",triumph:"unicode/1f624.png?v8",trolleybus:"unicode/1f68e.png?v8",trollface:"trollface.png?v8",trophy:"unicode/1f3c6.png?v8",tropical_drink:"unicode/1f379.png?v8",tropical_fish:"unicode/1f420.png?v8",truck:"unicode/1f69a.png?v8",trumpet:"unicode/1f3ba.png?v8",tshirt:"unicode/1f455.png?v8",tulip:"unicode/1f337.png?v8",tumbler_glass:"unicode/1f943.png?v8",tunisia:"unicode/1f1f9-1f1f3.png?v8",turkey:"unicode/1f983.png?v8",turkmenistan:"unicode/1f1f9-1f1f2.png?v8",turks_caicos_islands:"unicode/1f1f9-1f1e8.png?v8",turtle:"unicode/1f422.png?v8",tuvalu:"unicode/1f1f9-1f1fb.png?v8",tv:"unicode/1f4fa.png?v8",twisted_rightwards_arrows:"unicode/1f500.png?v8",two:"unicode/0032-20e3.png?v8",two_hearts:"unicode/1f495.png?v8",two_men_holding_hands:"unicode/1f46c.png?v8",two_women_holding_hands:"unicode/1f46d.png?v8",u5272:"unicode/1f239.png?v8",u5408:"unicode/1f234.png?v8",u55b6:"unicode/1f23a.png?v8",u6307:"unicode/1f22f.png?v8",u6708:"unicode/1f237.png?v8",u6709:"unicode/1f236.png?v8",u6e80:"unicode/1f235.png?v8",u7121:"unicode/1f21a.png?v8",u7533:"unicode/1f238.png?v8",u7981:"unicode/1f232.png?v8",u7a7a:"unicode/1f233.png?v8",uganda:"unicode/1f1fa-1f1ec.png?v8",uk:"unicode/1f1ec-1f1e7.png?v8",ukraine:"unicode/1f1fa-1f1e6.png?v8",umbrella:"unicode/2614.png?v8",unamused:"unicode/1f612.png?v8",underage:"unicode/1f51e.png?v8",unicorn:"unicode/1f984.png?v8",united_arab_emirates:"unicode/1f1e6-1f1ea.png?v8",united_nations:"unicode/1f1fa-1f1f3.png?v8",unlock:"unicode/1f513.png?v8",up:"unicode/1f199.png?v8",upside_down_face:"unicode/1f643.png?v8",uruguay:"unicode/1f1fa-1f1fe.png?v8",us:"unicode/1f1fa-1f1f8.png?v8",us_outlying_islands:"unicode/1f1fa-1f1f2.png?v8",us_virgin_islands:"unicode/1f1fb-1f1ee.png?v8",uzbekistan:"unicode/1f1fa-1f1ff.png?v8",v:"unicode/270c.png?v8",vampire:"unicode/1f9db.png?v8",vampire_man:"unicode/1f9db-2642.png?v8",vampire_woman:"unicode/1f9db-2640.png?v8",vanuatu:"unicode/1f1fb-1f1fa.png?v8",vatican_city:"unicode/1f1fb-1f1e6.png?v8",venezuela:"unicode/1f1fb-1f1ea.png?v8",vertical_traffic_light:"unicode/1f6a6.png?v8",vhs:"unicode/1f4fc.png?v8",vibration_mode:"unicode/1f4f3.png?v8",video_camera:"unicode/1f4f9.png?v8",video_game:"unicode/1f3ae.png?v8",vietnam:"unicode/1f1fb-1f1f3.png?v8",violin:"unicode/1f3bb.png?v8",virgo:"unicode/264d.png?v8",volcano:"unicode/1f30b.png?v8",volleyball:"unicode/1f3d0.png?v8",vomiting_face:"unicode/1f92e.png?v8",vs:"unicode/1f19a.png?v8",vulcan_salute:"unicode/1f596.png?v8",waffle:"unicode/1f9c7.png?v8",wales:"unicode/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png?v8",walking:"unicode/1f6b6.png?v8",walking_man:"unicode/1f6b6-2642.png?v8",walking_woman:"unicode/1f6b6-2640.png?v8",wallis_futuna:"unicode/1f1fc-1f1eb.png?v8",waning_crescent_moon:"unicode/1f318.png?v8",waning_gibbous_moon:"unicode/1f316.png?v8",warning:"unicode/26a0.png?v8",wastebasket:"unicode/1f5d1.png?v8",watch:"unicode/231a.png?v8",water_buffalo:"unicode/1f403.png?v8",water_polo:"unicode/1f93d.png?v8",watermelon:"unicode/1f349.png?v8",wave:"unicode/1f44b.png?v8",wavy_dash:"unicode/3030.png?v8",waxing_crescent_moon:"unicode/1f312.png?v8",waxing_gibbous_moon:"unicode/1f314.png?v8",wc:"unicode/1f6be.png?v8",weary:"unicode/1f629.png?v8",wedding:"unicode/1f492.png?v8",weight_lifting:"unicode/1f3cb.png?v8",weight_lifting_man:"unicode/1f3cb-2642.png?v8",weight_lifting_woman:"unicode/1f3cb-2640.png?v8",western_sahara:"unicode/1f1ea-1f1ed.png?v8",whale:"unicode/1f433.png?v8",whale2:"unicode/1f40b.png?v8",wheel_of_dharma:"unicode/2638.png?v8",wheelchair:"unicode/267f.png?v8",white_check_mark:"unicode/2705.png?v8",white_circle:"unicode/26aa.png?v8",white_flag:"unicode/1f3f3.png?v8",white_flower:"unicode/1f4ae.png?v8",white_haired_man:"unicode/1f468-1f9b3.png?v8",white_haired_woman:"unicode/1f469-1f9b3.png?v8",white_heart:"unicode/1f90d.png?v8",white_large_square:"unicode/2b1c.png?v8",white_medium_small_square:"unicode/25fd.png?v8",white_medium_square:"unicode/25fb.png?v8",white_small_square:"unicode/25ab.png?v8",white_square_button:"unicode/1f533.png?v8",wilted_flower:"unicode/1f940.png?v8",wind_chime:"unicode/1f390.png?v8",wind_face:"unicode/1f32c.png?v8",window:"unicode/1fa9f.png?v8",wine_glass:"unicode/1f377.png?v8",wink:"unicode/1f609.png?v8",wolf:"unicode/1f43a.png?v8",woman:"unicode/1f469.png?v8",woman_artist:"unicode/1f469-1f3a8.png?v8",woman_astronaut:"unicode/1f469-1f680.png?v8",woman_beard:"unicode/1f9d4-2640.png?v8",woman_cartwheeling:"unicode/1f938-2640.png?v8",woman_cook:"unicode/1f469-1f373.png?v8",woman_dancing:"unicode/1f483.png?v8",woman_facepalming:"unicode/1f926-2640.png?v8",woman_factory_worker:"unicode/1f469-1f3ed.png?v8",woman_farmer:"unicode/1f469-1f33e.png?v8",woman_feeding_baby:"unicode/1f469-1f37c.png?v8",woman_firefighter:"unicode/1f469-1f692.png?v8",woman_health_worker:"unicode/1f469-2695.png?v8",woman_in_manual_wheelchair:"unicode/1f469-1f9bd.png?v8",woman_in_motorized_wheelchair:"unicode/1f469-1f9bc.png?v8",woman_in_tuxedo:"unicode/1f935-2640.png?v8",woman_judge:"unicode/1f469-2696.png?v8",woman_juggling:"unicode/1f939-2640.png?v8",woman_mechanic:"unicode/1f469-1f527.png?v8",woman_office_worker:"unicode/1f469-1f4bc.png?v8",woman_pilot:"unicode/1f469-2708.png?v8",woman_playing_handball:"unicode/1f93e-2640.png?v8",woman_playing_water_polo:"unicode/1f93d-2640.png?v8",woman_scientist:"unicode/1f469-1f52c.png?v8",woman_shrugging:"unicode/1f937-2640.png?v8",woman_singer:"unicode/1f469-1f3a4.png?v8",woman_student:"unicode/1f469-1f393.png?v8",woman_teacher:"unicode/1f469-1f3eb.png?v8",woman_technologist:"unicode/1f469-1f4bb.png?v8",woman_with_headscarf:"unicode/1f9d5.png?v8",woman_with_probing_cane:"unicode/1f469-1f9af.png?v8",woman_with_turban:"unicode/1f473-2640.png?v8",woman_with_veil:"unicode/1f470-2640.png?v8",womans_clothes:"unicode/1f45a.png?v8",womans_hat:"unicode/1f452.png?v8",women_wrestling:"unicode/1f93c-2640.png?v8",womens:"unicode/1f6ba.png?v8",wood:"unicode/1fab5.png?v8",woozy_face:"unicode/1f974.png?v8",world_map:"unicode/1f5fa.png?v8",worm:"unicode/1fab1.png?v8",worried:"unicode/1f61f.png?v8",wrench:"unicode/1f527.png?v8",wrestling:"unicode/1f93c.png?v8",writing_hand:"unicode/270d.png?v8",x:"unicode/274c.png?v8",yarn:"unicode/1f9f6.png?v8",yawning_face:"unicode/1f971.png?v8",yellow_circle:"unicode/1f7e1.png?v8",yellow_heart:"unicode/1f49b.png?v8",yellow_square:"unicode/1f7e8.png?v8",yemen:"unicode/1f1fe-1f1ea.png?v8",yen:"unicode/1f4b4.png?v8",yin_yang:"unicode/262f.png?v8",yo_yo:"unicode/1fa80.png?v8",yum:"unicode/1f60b.png?v8",zambia:"unicode/1f1ff-1f1f2.png?v8",zany_face:"unicode/1f92a.png?v8",zap:"unicode/26a1.png?v8",zebra:"unicode/1f993.png?v8",zero:"unicode/0030-20e3.png?v8",zimbabwe:"unicode/1f1ff-1f1fc.png?v8",zipper_mouth_face:"unicode/1f910.png?v8",zombie:"unicode/1f9df.png?v8",zombie_man:"unicode/1f9df-2642.png?v8",zombie_woman:"unicode/1f9df-2640.png?v8",zzz:"unicode/1f4a4.png?v8"}};function jn(e,t){return e.replace(/<(code|pre|script|template)[^>]*?>[\s\S]+?<\/(code|pre|script|template)>/g,function(e){return e.replace(/:/g,"__colon__")}).replace(/<!--[\s\S]+?-->/g,function(e){return e.replace(/:/g,"__colon__")}).replace(/([a-z]{2,}:)?\/\/[^\s'">)]+/gi,function(e){return e.replace(/:/g,"__colon__")}).replace(/:([a-z0-9_\-+]+?):/g,function(e,n){return i=e,o=n,e=t,n=Rn.data[o],i,i=n?e&&/unicode/.test(n)?'<span class="emoji">'+n.replace("unicode/","").replace(/\.png.*/,"").split("-").map(function(e){return"&#x"+e+";"}).join("‍").concat("︎")+"</span>":'<img src="'+Rn.baseURL+n+'.png" alt="'+o+'" class="emoji" loading="lazy">':i;var i,o}).replace(/__colon__/g,":")}function On(e){var o={};return{str:e=(e=void 0===e?"":e)&&e.replace(/^('|")/,"").replace(/('|")$/,"").replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g,function(e,n,i){return-1===n.indexOf(":")?(o[n]=i&&i.replace(/"/g,"")||!0,""):e}).trim(),config:o}}function Ln(e){return(e=void 0===e?"":e).replace(/(<\/?a.*?>)/gi,"")}var qn,Pn=be(function(e){var u,f,p,d,n,g=function(u){var i=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,n=0,e={},T={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof C?new C(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++n}),e.__id},clone:function i(e,o){var t,n;switch(o=o||{},T.util.type(e)){case"Object":if(n=T.util.objId(e),o[n])return o[n];for(var a in t={},o[n]=t,e)e.hasOwnProperty(a)&&(t[a]=i(e[a],o));return t;case"Array":return(n=T.util.objId(e),o[n])?o[n]:(t=[],o[n]=t,e.forEach(function(e,n){t[n]=i(e,o)}),t);default:return e}},getLanguage:function(e){for(;e;){var n=i.exec(e.className);if(n)return n[1].toLowerCase();e=e.parentElement}return"none"},setLanguage:function(e,n){e.className=e.className.replace(RegExp(i,"gi"),""),e.classList.add("language-"+n)},currentScript:function(){if("undefined"==typeof document)return null;if("currentScript"in document)return document.currentScript;try{throw new Error}catch(e){var n=(/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(e.stack)||[])[1];if(n){var i,o=document.getElementsByTagName("script");for(i in o)if(o[i].src==n)return o[i]}return null}},isActive:function(e,n,i){for(var o="no-"+n;e;){var t=e.classList;if(t.contains(n))return!0;if(t.contains(o))return!1;e=e.parentElement}return!!i}},languages:{plain:e,plaintext:e,text:e,txt:e,extend:function(e,n){var i,o=T.util.clone(T.languages[e]);for(i in n)o[i]=n[i];return o},insertBefore:function(i,e,n,o){var t,a=(o=o||T.languages)[i],r={};for(t in a)if(a.hasOwnProperty(t)){if(t==e)for(var c in n)n.hasOwnProperty(c)&&(r[c]=n[c]);n.hasOwnProperty(t)||(r[t]=a[t])}var u=o[i];return o[i]=r,T.languages.DFS(T.languages,function(e,n){n===u&&e!=i&&(this[e]=r)}),r},DFS:function e(n,i,o,t){t=t||{};var a,r,c,u=T.util.objId;for(a in n)n.hasOwnProperty(a)&&(i.call(n,a,n[a],o||a),r=n[a],"Object"!==(c=T.util.type(r))||t[u(r)]?"Array"!==c||t[u(r)]||(t[u(r)]=!0,e(r,i,a,t)):(t[u(r)]=!0,e(r,i,null,t)))}},plugins:{},highlightAll:function(e,n){T.highlightAllUnder(document,e,n)},highlightAllUnder:function(e,n,i){var o={callback:i,container:e,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};T.hooks.run("before-highlightall",o),o.elements=Array.prototype.slice.apply(o.container.querySelectorAll(o.selector)),T.hooks.run("before-all-elements-highlight",o);for(var t,a=0;t=o.elements[a++];)T.highlightElement(t,!0===n,o.callback)},highlightElement:function(e,n,i){var o=T.util.getLanguage(e),t=T.languages[o];T.util.setLanguage(e,o);var a=e.parentElement;a&&"pre"===a.nodeName.toLowerCase()&&T.util.setLanguage(a,o);var r={element:e,language:o,grammar:t,code:e.textContent};function c(e){r.highlightedCode=e,T.hooks.run("before-insert",r),r.element.innerHTML=r.highlightedCode,T.hooks.run("after-highlight",r),T.hooks.run("complete",r),i&&i.call(r.element)}if(T.hooks.run("before-sanity-check",r),(a=r.element.parentElement)&&"pre"===a.nodeName.toLowerCase()&&!a.hasAttribute("tabindex")&&a.setAttribute("tabindex","0"),!r.code)return T.hooks.run("complete",r),void(i&&i.call(r.element));T.hooks.run("before-highlight",r),r.grammar?n&&u.Worker?((n=new Worker(T.filename)).onmessage=function(e){c(e.data)},n.postMessage(JSON.stringify({language:r.language,code:r.code,immediateClose:!0}))):c(T.highlight(r.code,r.grammar,r.language)):c(T.util.encode(r.code))},highlight:function(e,n,i){i={code:e,grammar:n,language:i};if(T.hooks.run("before-tokenize",i),!i.grammar)throw new Error('The language "'+i.language+'" has no grammar.');return i.tokens=T.tokenize(i.code,i.grammar),T.hooks.run("after-tokenize",i),C.stringify(T.util.encode(i.tokens),i.language)},tokenize:function(e,n){var i=n.rest;if(i){for(var o in i)n[o]=i[o];delete n.rest}var t=new a;return j(t,t.head,e),function e(n,i,o,t,a,r){for(var c in o)if(o.hasOwnProperty(c)&&o[c]){var u=o[c];u=Array.isArray(u)?u:[u];for(var f=0;f<u.length;++f){if(r&&r.cause==c+","+f)return;var p,d=u[f],g=d.inside,s=!!d.lookbehind,l=!!d.greedy,v=d.alias;l&&!d.pattern.global&&(p=d.pattern.toString().match(/[imsuy]*$/)[0],d.pattern=RegExp(d.pattern.source,p+"g"));for(var h=d.pattern||d,_=t.next,m=a;_!==i.tail&&!(r&&m>=r.reach);m+=_.value.length,_=_.next){var b=_.value;if(i.length>n.length)return;if(!(b instanceof C)){var k,w=1;if(l){if(!(k=R(h,m,n,s))||k.index>=n.length)break;var y=k.index,x=k.index+k[0].length,S=m;for(S+=_.value.length;S<=y;)_=_.next,S+=_.value.length;if(S-=_.value.length,m=S,_.value instanceof C)continue;for(var A=_;A!==i.tail&&(S<x||"string"==typeof A.value);A=A.next)w++,S+=A.value.length;w--,b=n.slice(m,S),k.index-=m}else if(!(k=R(h,0,b,s)))continue;var y=k.index,$=k[0],z=b.slice(0,y),F=b.slice(y+$.length),E=m+b.length;r&&E>r.reach&&(r.reach=E);b=_.prev;z&&(b=j(i,b,z),m+=z.length),O(i,b,w);$=new C(c,g?T.tokenize($,g):$,v,$);_=j(i,b,$),F&&j(i,_,F),1<w&&(E={cause:c+","+f,reach:E},e(n,i,o,_.prev,m,E),r&&E.reach>r.reach&&(r.reach=E.reach))}}}}}(e,t,n,t.head,0),function(e){var n=[],i=e.head.next;for(;i!==e.tail;)n.push(i.value),i=i.next;return n}(t)},hooks:{all:{},add:function(e,n){var i=T.hooks.all;i[e]=i[e]||[],i[e].push(n)},run:function(e,n){var i=T.hooks.all[e];if(i&&i.length)for(var o,t=0;o=i[t++];)o(n)}},Token:C};function C(e,n,i,o){this.type=e,this.content=n,this.alias=i,this.length=0|(o||"").length}function R(e,n,i,o){e.lastIndex=n;i=e.exec(i);return i&&o&&i[1]&&(o=i[1].length,i.index+=o,i[0]=i[0].slice(o)),i}function a(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function j(e,n,i){var o=n.next,i={value:i,prev:n,next:o};return n.next=i,o.prev=i,e.length++,i}function O(e,n,i){for(var o=n.next,t=0;t<i&&o!==e.tail;t++)o=o.next;(n.next=o).prev=n,e.length-=t}if(u.Prism=T,C.stringify=function n(e,i){if("string"==typeof e)return e;if(Array.isArray(e)){var o="";return e.forEach(function(e){o+=n(e,i)}),o}var t={type:e.type,content:n(e.content,i),tag:"span",classes:["token",e.type],attributes:{},language:i},e=e.alias;e&&(Array.isArray(e)?Array.prototype.push.apply(t.classes,e):t.classes.push(e)),T.hooks.run("wrap",t);var a,r="";for(a in t.attributes)r+=" "+a+'="'+(t.attributes[a]||"").replace(/"/g,""")+'"';return"<"+t.tag+' class="'+t.classes.join(" ")+'"'+r+">"+t.content+"</"+t.tag+">"},!u.document)return u.addEventListener&&(T.disableWorkerMessageHandler||u.addEventListener("message",function(e){var n=JSON.parse(e.data),i=n.language,e=n.code,n=n.immediateClose;u.postMessage(T.highlight(e,T.languages[i],i)),n&&u.close()},!1)),T;var o=T.util.currentScript();function t(){T.manual||T.highlightAll()}return o&&(T.filename=o.src,o.hasAttribute("data-manual")&&(T.manual=!0)),T.manual||("loading"===(e=document.readyState)||"interactive"===e&&o&&o.defer?document.addEventListener("DOMContentLoaded",t):window.requestAnimationFrame?window.requestAnimationFrame(t):window.setTimeout(t,16)),T}("undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{});e.exports&&(e.exports=g),void 0!==me&&(me.Prism=g),g.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},g.languages.markup.tag.inside["attr-value"].inside.entity=g.languages.markup.entity,g.languages.markup.doctype.inside["internal-subset"].inside=g.languages.markup,g.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))}),Object.defineProperty(g.languages.markup.tag,"addInlined",{value:function(e,n){var i={};i["language-"+n]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:g.languages[n]},i.cdata=/^<!\[CDATA\[|\]\]>$/i;i={"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:i}};i["language-"+n]={pattern:/[\s\S]+/,inside:g.languages[n]};n={};n[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g,function(){return e}),"i"),lookbehind:!0,greedy:!0,inside:i},g.languages.insertBefore("markup","cdata",n)}}),Object.defineProperty(g.languages.markup.tag,"addAttribute",{value:function(e,n){g.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[n,"language-"+n],inside:g.languages[n]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),g.languages.html=g.languages.markup,g.languages.mathml=g.languages.markup,g.languages.svg=g.languages.markup,g.languages.xml=g.languages.extend("markup",{}),g.languages.ssml=g.languages.xml,g.languages.atom=g.languages.xml,g.languages.rss=g.languages.xml,function(e){var n=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+n.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+n.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+n.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:n,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;e=e.languages.markup;e&&(e.tag.addInlined("style","css"),e.tag.addAttribute("style","css"))}(g),g.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},g.languages.javascript=g.languages.extend("clike",{"class-name":[g.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),g.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,g.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:g.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:g.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:g.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:g.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:g.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),g.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:g.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),g.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),g.languages.markup&&(g.languages.markup.tag.addInlined("script","javascript"),g.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),g.languages.js=g.languages.javascript,void 0!==g&&"undefined"!=typeof document&&(Element.prototype.matches||(Element.prototype.matches=Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector),u={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"},d="pre[data-src]:not(["+(f="data-src-status")+'="loaded"]):not(['+f+'="'+(p="loading")+'"])',g.hooks.add("before-highlightall",function(e){e.selector+=", "+d}),g.hooks.add("before-sanity-check",function(e){var t,n,i,o,a,r,c=e.element;c.matches(d)&&(e.code="",c.setAttribute(f,p),(t=c.appendChild(document.createElement("CODE"))).textContent="Loading…",i=c.getAttribute("data-src"),"none"===(e=e.language)&&(n=(/\.(\w+)$/.exec(i)||[,"none"])[1],e=u[n]||n),g.util.setLanguage(t,e),g.util.setLanguage(c,e),(n=g.plugins.autoloader)&&n.loadLanguages(e),i=i,o=function(e){c.setAttribute(f,"loaded");var n,i,o=function(e){if(i=/^\s*(\d+)\s*(?:(,)\s*(?:(\d+)\s*)?)?$/.exec(e||"")){var n=Number(i[1]),e=i[2],i=i[3];return e?i?[n,Number(i)]:[n,void 0]:[n,n]}}(c.getAttribute("data-range"));o&&(n=e.split(/\r\n?|\n/g),i=o[0],o=null==o[1]?n.length:o[1],i<0&&(i+=n.length),i=Math.max(0,Math.min(i-1,n.length)),o<0&&(o+=n.length),o=Math.max(0,Math.min(o,n.length)),e=n.slice(i,o).join("\n"),c.hasAttribute("data-start")||c.setAttribute("data-start",String(i+1))),t.textContent=e,g.highlightElement(t)},a=function(e){c.setAttribute(f,"failed"),t.textContent=e},(r=new XMLHttpRequest).open("GET",i,!0),r.onreadystatechange=function(){4==r.readyState&&(r.status<400&&r.responseText?o(r.responseText):400<=r.status?a("✖ Error "+r.status+" while fetching file: "+r.statusText):a("✖ Error: File does not exist or is empty"))},r.send(null))}),n=!(g.plugins.fileHighlight={highlight:function(e){for(var n,i=(e||document).querySelectorAll(d),o=0;n=i[o++];)g.highlightElement(n)}}),g.fileHighlight=function(){n||(console.warn("Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead."),n=!0),g.plugins.fileHighlight.highlight.apply(this,arguments)})});function Mn(e,n){return"___"+e.toUpperCase()+n+"___"}qn=Prism,Object.defineProperties(qn.languages["markup-templating"]={},{buildPlaceholders:{value:function(o,t,e,a){var r;o.language===t&&(r=o.tokenStack=[],o.code=o.code.replace(e,function(e){if("function"==typeof a&&!a(e))return e;for(var n,i=r.length;-1!==o.code.indexOf(n=Mn(t,i));)++i;return r[i]=e,n}),o.grammar=qn.languages.markup)}},tokenizePlaceholders:{value:function(f,p){var d,g;f.language===p&&f.tokenStack&&(f.grammar=qn.languages[p],d=0,g=Object.keys(f.tokenStack),function e(n){for(var i=0;i<n.length&&!(d>=g.length);i++){var o,t,a,r,c,u=n[i];"string"==typeof u||u.content&&"string"==typeof u.content?(t=g[d],a=f.tokenStack[t],o="string"==typeof u?u:u.content,c=Mn(p,t),-1<(r=o.indexOf(c))&&(++d,t=o.substring(0,r),a=new qn.Token(p,qn.tokenize(a,f.grammar),"language-"+p,a),r=o.substring(r+c.length),c=[],t&&c.push.apply(c,e([t])),c.push(a),r&&c.push.apply(c,e([r])),"string"==typeof u?n.splice.apply(n,[i,1].concat(c)):u.content=c)):u.content&&e(u.content)}return n}(f.tokens))}}});function In(t,e){var a=this;this.config=t,this.router=e,this.cacheTree={},this.toc=[],this.cacheTOC={},this.linkTarget=t.externalLinkTarget||"_blank",this.linkRel="_blank"===this.linkTarget?t.externalLinkRel||"noopener":"",this.contentBase=e.getBasePath();var n=this._initRenderer();this.heading=n.heading;var r=o(e=t.markdown||{})?e(Sn,n):(Sn.setOptions(m(e,{renderer:m(n,e.renderer)})),Sn);this._marked=r,this.compile=function(i){var o=!0,e=c(function(e){o=!1;var n="";return i&&(n=f(i)?r(i):r.parser(i),n=t.noEmoji?n:jn(n,t.nativeEmoji),Cn.clear(),n)})(i),n=a.router.parse().file;return o?a.toc=a.cacheTOC[n]:a.cacheTOC[n]=[].concat(a.toc),e}}var Nn={},Hn={markdown:function(e){return{url:e}},mermaid:function(e){return{url:e}},iframe:function(e,n){return{html:'<iframe src="'+e+'" '+(n||"width=100% height=400")+"></iframe>"}},video:function(e,n){return{html:'<video src="'+e+'" '+(n||"controls")+">Not Support</video>"}},audio:function(e,n){return{html:'<audio src="'+e+'" '+(n||"controls")+">Not Support</audio>"}},code:function(e,n){var i=e.match(/\.(\w+)$/);return{url:e,lang:i="md"===(i=n||i&&i[1])?"markdown":i}}};In.prototype.compileEmbed=function(e,n){var i,o,t=On(n),a=t.str,t=t.config;if(n=a,t.include)return T(e)||(e=q(this.contentBase,R(this.router.getCurrentPath()),e)),t.type&&(o=Hn[t.type])?(i=o.call(this,e,n)).type=t.type:(o="code",/\.(md|markdown)/.test(e)?o="markdown":/\.mmd/.test(e)?o="mermaid":/\.html?/.test(e)?o="iframe":/\.(mp4|ogg)/.test(e)?o="video":/\.mp3/.test(e)&&(o="audio"),(i=Hn[o].call(this,e,n)).type=o),i.fragment=t.fragment,i},In.prototype._matchNotCompileLink=function(e){for(var n=this.config.noCompileLinks||[],i=0;i<n.length;i++){var o=n[i];if((Nn[o]||(Nn[o]=new RegExp("^"+o+"$"))).test(e))return e}},In.prototype._initRenderer=function(){var r,c,u,f,p,d,e=new Sn.Renderer,n=this.linkTarget,i=this.linkRel,a=this.router,o=this.contentBase,g=this,t={};return t.heading=e.heading=function(e,n){var i=On(e),o=i.str,t=i.config,e={level:n,title:Ln(o)};/<!-- {docsify-ignore} -->/g.test(o)&&(o=o.replace("\x3c!-- {docsify-ignore} --\x3e",""),e.title=Ln(o),e.ignoreSubHeading=!0),/{docsify-ignore}/g.test(o)&&(o=o.replace("{docsify-ignore}",""),e.title=Ln(o),e.ignoreSubHeading=!0),/<!-- {docsify-ignore-all} -->/g.test(o)&&(o=o.replace("\x3c!-- {docsify-ignore-all} --\x3e",""),e.title=Ln(o),e.ignoreAllSubs=!0),/{docsify-ignore-all}/g.test(o)&&(o=o.replace("{docsify-ignore-all}",""),e.title=Ln(o),e.ignoreAllSubs=!0);i=Cn(t.id||o),t=a.toURL(a.getCurrentPath(),{id:i});return e.slug=t,g.toc.push(e),"<h"+n+' id="'+i+'"><a href="'+t+'" data-id="'+i+'" class="anchor"><span>'+o+"</span></a></h"+n+">"},t.code={renderer:e}.renderer.code=function(e,n){var i=Pn.languages[n=void 0===n?"markup":n]||Pn.languages.markup;return'<pre v-pre data-lang="'+n+'"><code class="lang-'+n+'">'+Pn.highlight(e.replace(/@DOCSIFY_QM@/g,"`"),i,n)+"</code></pre>"},t.link=(i=(n={renderer:e,router:a,linkTarget:n,linkRel:i,compilerClass:g}).renderer,c=n.router,u=n.linkTarget,n.linkRel,f=n.compilerClass,i.link=function(e,n,i){var o=[],t=On(n=void 0===n?"":n),a=t.str,t=t.config;return u=t.target||u,r="_blank"===u?f.config.externalLinkRel||"noopener":"",n=a,T(e)||f._matchNotCompileLink(e)||t.ignore?(T(e)||"./"!==e.slice(0,2)||(e=document.URL.replace(/\/(?!.*\/).*/,"/").replace("#/./","")+e),o.push(0===e.indexOf("mailto:")?"":'target="'+u+'"'),o.push(0!==e.indexOf("mailto:")&&""!==r?' rel="'+r+'"':"")):(e===f.config.homepage&&(e="README"),e=c.toURL(e,null,c.getCurrentPath())),t.crossorgin&&"_self"===u&&"history"===f.config.routerMode&&-1===f.config.crossOriginLinks.indexOf(e)&&f.config.crossOriginLinks.push(e),t.disabled&&(o.push("disabled"),e="javascript:void(0)"),t.class&&o.push('class="'+t.class+'"'),t.id&&o.push('id="'+t.id+'"'),n&&o.push('title="'+n+'"'),'<a href="'+e+'" '+o.join(" ")+">"+i+"</a>"}),t.paragraph={renderer:e}.renderer.paragraph=function(e){e=/^!>/.test(e)?$n("tip",e):/^\?>/.test(e)?$n("warn",e):"<p>"+e+"</p>";return e},t.image=(o=(i={renderer:e,contentBase:o,router:a}).renderer,p=i.contentBase,d=i.router,o.image=function(e,n,i){var o=e,t=[],a=On(n),r=a.str,a=a.config;return n=r,a["no-zoom"]&&t.push("data-no-zoom"),n&&t.push('title="'+n+'"'),a.size&&(n=(r=a.size.split("x"))[0],(r=r[1])?t.push('width="'+n+'" height="'+r+'"'):t.push('width="'+n+'"')),a.class&&t.push('class="'+a.class+'"'),a.id&&t.push('id="'+a.id+'"'),T(e)||(o=q(p,R(d.getCurrentPath()),e)),0<t.length?'<img src="'+o+'" data-origin="'+e+'" alt="'+i+'" '+t.join(" ")+" />":'<img src="'+o+'" data-origin="'+e+'" alt="'+i+'"'+t+">"}),t.list={renderer:e}.renderer.list=function(e,n,i){n=n?"ol":"ul";return"<"+n+" "+[/<li class="task-list-item">/.test(e.split('class="task-list"')[0])?'class="task-list"':"",i&&1<i?'start="'+i+'"':""].join(" ").trim()+">"+e+"</"+n+">"},t.listitem={renderer:e}.renderer.listitem=function(e){return/^(<input.*type="checkbox"[^>]*>)/.test(e)?'<li class="task-list-item"><label>'+e+"</label></li>":"<li>"+e+"</li>"},e.origin=t,e},In.prototype.sidebar=function(e,n){var i=this.toc,o=this.router.getCurrentPath(),t="";if(e)t=this.compile(e);else{for(var a=0;a<i.length;a++)if(i[a].ignoreSubHeading){var r=i[a].level;i.splice(a,1);for(var c=a;c<i.length&&r<i[c].level;c++)i.splice(c,1)&&c--&&a++;a--}n=this.cacheTree[o]||zn(i,n),t=An(n,"<ul>{inner}</ul>");this.cacheTree[o]=n}return t},In.prototype.subSidebar=function(e){if(e){var n=this.router.getCurrentPath(),i=this.cacheTree,o=this.toc;o[0]&&o[0].ignoreAllSubs&&o.splice(0),o[0]&&1===o[0].level&&o.shift();for(var t=0;t<o.length;t++)o[t].ignoreSubHeading&&o.splice(t,1)&&t--;e=i[n]||zn(o,e);return i[n]=e,this.toc=[],An(e)}this.toc=[]},In.prototype.header=function(e,n){return this.heading(e,n)},In.prototype.article=function(e){return this.compile(e)},In.prototype.cover=function(e){var n=this.toc.slice(),e=this.compile(e);return this.toc=n.slice(),e};function Dn(e){var n=Zn(e);return 0===n?e:(n=new RegExp("^[ \\t]{"+n+"}","gm"),e.replace(n,""))}var Un,Zn=function(e){e=e.match(/^[ \t]*(?=\S)/gm);return e?e.reduce(function(e,n){return Math.min(e,n.length)},1/0):0},Bn={};function Vn(e,o){var a=e.compiler,t=e.raw;void 0===t&&(t="");var n=e.fetch,e=Bn[t];if(e){var i=e.slice();return i.links=e.links,o(i)}var i=a._marked,r=i.lexer(t),c=[],u=i.Lexer.rules.inline.link,f=r.links;r.forEach(function(e,t){"paragraph"===e.type&&(e.text=e.text.replace(new RegExp(u.source,"g"),function(e,n,i,o){o=a.compileEmbed(i,o);return o&&c.push({index:t,embed:o}),e}))});var p=[];!function(e,a){var n,i=e.embedTokens,r=e.compile,c=(e.fetch,0),u=1;if(!i.length)return a({});for(;n=i[c++];){var o=function(t){return function(e){var n,i,o;e&&("markdown"===t.embed.type?((i=t.embed.url.split("/")).pop(),i=i.join("/"),e=e.replace(/\[([^[\]]+)\]\(([^)]+)\)/g,function(e){var n=e.indexOf("(");return"(."===e.slice(n,n+2)?e.substring(0,n)+"("+window.location.protocol+"//"+window.location.host+i+"/"+e.substring(n+1,e.length-1)+")":e}),!0===(($docsify.frontMatter||{}).installed||!1)&&(e=$docsify.frontMatter.parseMarkdown(e)),n=r.lexer(e)):"code"===t.embed.type?(t.embed.fragment&&(o=t.embed.fragment,o=new RegExp("(?:###|\\/\\/\\/)\\s*\\["+o+"\\]([\\s\\S]*)(?:###|\\/\\/\\/)\\s*\\["+o+"\\]"),e=Dn((e.match(o)||[])[1]||"").trim()),n=r.lexer("```"+t.embed.lang+"\n"+e.replace(/`/g,"@DOCSIFY_QM@")+"\n```\n")):"mermaid"===t.embed.type?(n=[{type:"html",text:'<div class="mermaid">\n'+e+"\n</div>"}]).links={}:(n=[{type:"html",text:e}]).links={}),a({token:t,embedToken:n}),++u>=c&&a({})}}(n);n.embed.url?X(n.embed.url).then(o):o(n.embed.html)}}({compile:i,embedTokens:c,fetch:n},function(e){var n,i=e.embedToken,e=e.token;e?(n=e.index,p.forEach(function(e){n>e.start&&(n+=e.length)}),m(f,i.links),r=r.slice(0,n).concat(i,r.slice(n+1)),p.push({start:n,length:i.length-1})):(Bn[t]=r.concat(),r.links=Bn[t].links=f,o(r))})}function Yn(e,n,i){var o,t,a,r;return n="function"==typeof i?i(n):"string"==typeof i?(a=[],r=0,(o=i).replace(V,function(n,e,i){a.push(o.substring(r,i-1)),r=i+=n.length+1,a.push(t&&t[n]||function(e){return("00"+("string"==typeof Y[n]?e[Y[n]]():Y[n](e))).slice(-n.length)})}),r!==o.length&&a.push(o.substring(r)),function(e){for(var n="",i=0,o=e||new Date;i<a.length;i++)n+="string"==typeof a[i]?a[i]:a[i](o);return n}(new Date(n))):n,e.replace(/{docsify-updated}/g,n)}function Gn(e){function n(e){var n=Boolean(e.__vue__&&e.__vue__._isVue),e=Boolean(e._vnode&&e._vnode.__v_skip);return n||e}var i=this.config,o=b(".markdown-section"),t="Vue"in window&&window.Vue.version&&Number(window.Vue.version.charAt(0));if(e=e||"<h1>404 - Not found</h1>","Vue"in window)for(var a=0,r=k(".markdown-section > *").filter(n);a<r.length;a+=1){var c=r[a];2===t?c.__vue__.$destroy():3===t&&c.__vue_app__.unmount()}if(this._renderTo(o,e),i.loadSidebar||this._renderSidebar(),(i.executeScript||"Vue"in window&&!1!==i.executeScript)&&(!(e=k(".markdown-section>script").filter(function(e){return!/template/.test(e.type)})[0])||(e=e.innerText.trim())&&new Function(e)()),"Vue"in window){var u,f,p=[],d=Object.keys(i.vueComponents||{});2===t&&d.length&&d.forEach(function(e){window.Vue.options.components[e]||window.Vue.component(e,i.vueComponents[e])}),!Un&&i.vueGlobalOptions&&"function"==typeof i.vueGlobalOptions.data&&(Un=i.vueGlobalOptions.data()),p.push.apply(p,Object.keys(i.vueMounts||{}).map(function(e){return[b(o,e),i.vueMounts[e]]}).filter(function(e){var n=e[0];e[1];return n})),(i.vueGlobalOptions||d.length)&&(u=/{{2}[^{}]*}{2}/,f=/<[^>/]+\s([@:]|v-)[\w-:.[\]]+[=>\s]/,p.push.apply(p,k(".markdown-section > *").filter(function(i){return!p.some(function(e){var n=e[0];e[1];return n===i})}).filter(function(e){return e.tagName.toLowerCase()in(i.vueComponents||{})||e.querySelector(d.join(",")||null)||u.test(e.outerHTML)||f.test(e.outerHTML)}).map(function(e){var n=m({},i.vueGlobalOptions||{});return Un&&(n.data=function(){return Un}),[e,n]})));for(var g=0,s=p;g<s.length;g+=1){var l,v=s[g],h=v[0],_=v[1],v="data-isvue";h.matches("pre, script")||n(h)||h.querySelector("["+v+"]")||(h.setAttribute(v,""),2===t?(_.el=void 0,new window.Vue(_).$mount(h)):3===t&&(l=window.Vue.createApp(_),d.forEach(function(e){var n=i.vueComponents[e];l.component(e,n)}),l.mount(h)))}}}function Wn(n,i,o,t,a,e){n=e?n:n.replace(/\/$/,""),(n=R(n))&&X(a.router.getFile(n+o)+i,!1,a.config.requestHeaders).then(t,function(e){return Wn(n,i,o,t,a)})}function Xn(){var n=function(){return null};return[function(e){n(e)},function(e){n=e}]}Me=Object.freeze({__proto__:null,cached:c,hyphenate:a,hasOwn:u,merge:m,isPrimitive:f,noop:d,isFn:o,isExternal:g,inBrowser:!0,isMobile:s,supportsPushState:t,parseQuery:F,stringifyQuery:E,isAbsolutePath:T,removeParams:C,getParentPath:R,cleanPath:j,resolvePath:O,getPath:q,replaceSlug:P});var Qn,Jn=function(e){function n(){e.call(this),this.config=ue(this),this.initLifecycle(),this.initPlugin(),this.callHook("init"),this.initRouter(),this.initRender(),this.initEvent(),this.initFetch(),this.callHook("mounted")}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype.initPlugin=function(){var n=this;[].concat(this.config.plugins).forEach(function(e){try{o(e)&&e(n._lifecycle,n)}catch(e){if(!n.config.catchPluginErrors)throw e;console.error("Docsify plugin error",e)}})},n}((we=Object,function(e){function n(){e.apply(this,arguments)}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype._loadSideAndNav=function(e,n,i,o){var t=this;return function(){if(!i)return o();Wn(e,n,i,function(e){t._renderSidebar(e),o()},t,!0)}},n.prototype._fetch=function(i){var o=this;void 0===i&&(i=d);var t,e,n,a,r,c,u,f=this.route.query,p=this.route.path;g(p)?(history.replaceState(null,"","#"),this.router.normalize()):(t=E(f,["id"]),f=(e=this.config).loadNavbar,n=e.requestHeaders,a=e.loadSidebar,r=this.router.getFile(p),this.isRemoteUrl=g(r),this.isHTML=/\.html$/g.test(r),c=function(e,n){o._renderMain(e,n,o._loadSideAndNav(p,t,a,i))},u=function(e){o._fetchFallbackPage(p,t,i)||o._fetch404(r,t,i)},this.isRemoteUrl?Kn(r+t,0,n).then(c,u):this.matchVirtualRoute(p).then(function(e){"string"==typeof e?c(e):Kn(r+t,0,n).then(c,u)}),f&&Wn(p,t,f,function(e){return o._renderNav(e)},this,!0))},n.prototype._fetchCover=function(){var n=this,e=this.config,i=e.coverpage,o=e.requestHeaders,t=this.route.query,a=R(this.route.path);if(i){var r=null,e=this.route.path;"string"==typeof i?"/"===e&&(r=i):r=Array.isArray(i)?-1<i.indexOf(e)&&"_coverpage":!0===(e=i[e])?"_coverpage":e;var c=Boolean(r)&&this.config.onlyCover;return r?(r=this.router.getFile(a+r),this.coverIsHTML=/\.html$/g.test(r),X(r+E(t,["id"]),!1,o).then(function(e){return n._renderCover(e,c)})):this._renderCover(null,c),c}},n.prototype.$fetch=function(e,n){var i=this;void 0===e&&(e=d),void 0===n&&(n=this.$resetEvents.bind(this));function o(){i.callHook("doneEach"),e()}this._fetchCover()?o():this._fetch(function(){n(),o()})},n.prototype._fetchFallbackPage=function(i,o,t){var a=this;void 0===t&&(t=d);var e=this.config,n=e.requestHeaders,r=e.fallbackLanguages,c=e.loadSidebar;if(!r)return!1;e=i.split("/")[1];if(-1===r.indexOf(e))return!1;e=this.router.getFile(i.replace(new RegExp("^/"+e),""));return Kn(e+o,0,n).then(function(e,n){return a._renderMain(e,n,a._loadSideAndNav(i,o,c,t))},function(){return a._fetch404(i,o,t)}),!0},n.prototype._fetch404=function(e,n,i){var o=this,t=this.config,a=t.loadSidebar,r=t.requestHeaders,t=t.notFoundPage,c=this._loadSideAndNav(e,n,a,i=void 0===i?d:i);if(t){e=function(n,e){var i,o,t=e.notFoundPage,a="_404"+(e.ext||".md");switch(typeof t){case"boolean":o=a;break;case"string":o=t;break;case"object":o=(i=Object.keys(t).sort(function(e,n){return n.length-e.length}).filter(function(e){return n.match(new RegExp("^"+e))})[0])&&t[i]||a}return o}(e,this.config);return Kn(this.router.getFile(e),0,r).then(function(e,n){return o._renderMain(e,n,c)},function(){return o._renderMain(null,{},c)}),!0}return this._renderMain(null,{},c),!1},n.prototype.initFetch=function(){var e,n=this,i=this.config.loadSidebar;this.rendered?(e=ee(this.router,".sidebar-nav",!0,!0),i&&e&&(e.parentNode.innerHTML+=window.__SUB_SIDEBAR__),this._bindEventOnRendered(e),this.$resetEvents(),this.callHook("doneEach"),this.callHook("ready")):this.$fetch(function(e){return n.callHook("ready")})},n}(function(e){function n(){e.apply(this,arguments)}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype.$resetEvents=function(e){var n=this,i=this.config.auto2top;"history"!==e&&(n.route.query.id&&he(n.route.path,n.route.query.id),"navigate"===e&&i&&(i=i,_e.scrollTop=!0===(i=void 0===i?0:i)?0:Number(i))),this.config.loadNavbar&&ee(this.router,"nav")},n.prototype.initEvent=function(){function n(e){return h.classList.toggle("close")}var e;e="button.sidebar-toggle",this.router,null!=(e=l(e))&&(p(e,"click",function(e){e.stopPropagation(),n()}),s&&p(h,"click",function(e){return h.classList.contains("close")&&n()})),e=".sidebar",this.router,null!=(e=l(e))&&p(e,"click",function(e){e=e.target;"A"===e.nodeName&&e.nextSibling&&e.nextSibling.classList&&e.nextSibling.classList.contains("app-sub-sidebar")&&S(e.parentNode,"collapse")}),this.config.coverpage?s||p("scroll",K):h.classList.add("sticky")},n}(function(e){function n(){e.apply(this,arguments)}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype._renderTo=function(e,n,i){e=l(e);e&&(e[i?"outerHTML":"innerHTML"]=n)},n.prototype._renderSidebar=function(e){var n=this.config,i=n.maxLevel,o=n.subMaxLevel,t=n.loadSidebar;if(n.hideSidebar)return[document.querySelector("aside.sidebar"),document.querySelector("button.sidebar-toggle")].filter(function(e){return!!e}).forEach(function(e){return e.parentNode.removeChild(e)}),document.querySelector("section.content").style.right="unset",document.querySelector("section.content").style.left="unset",document.querySelector("section.content").style.position="relative",document.querySelector("section.content").style.width="100%",null;this._renderTo(".sidebar-nav",this.compiler.sidebar(e,i));i=ee(this.router,".sidebar-nav",!0,!0);t&&i?i.parentNode.innerHTML+=this.compiler.subSidebar(o)||"":this.compiler.subSidebar(),this._bindEventOnRendered(i)},n.prototype._bindEventOnRendered=function(e){var n,i=this.config.autoHeader;!function(e){var n=b(".cover.show");se=n?n.offsetHeight:0;for(var i,n=l(".sidebar"),o=[],t=0,a=(o=null!=n?k(n,"li"):o).length;t<a;t+=1){var r,c,u=o[t],f=u.querySelector("a");f&&("/"!==(r=f.getAttribute("href"))&&(f=(c=e.parse(r)).query.id,c=c.path,f&&(r=ve(c,f))),r&&(fe[decodeURIComponent(r)]=u))}s||(i=C(e.getCurrentPath()),x("scroll",function(){return le(i)}),p("scroll",function(){return le(i)}),p(n,"mouseover",function(){pe=!0}),p(n,"mouseleave",function(){pe=!1}))}(this.router),i&&e&&((i=(n=l("#main")).children[0])&&"H1"!==i.tagName&&y(n,w("div",this.compiler.header(e.innerText,1)).children[0]))},n.prototype._renderNav=function(e){e&&this._renderTo("nav",this.compiler.compile(e)),this.config.loadNavbar&&ee(this.router,"nav")},n.prototype._renderMain=function(o,t,a){var r=this;if(void 0===t&&(t={}),!o)return Gn.call(this,o);this.callHook("beforeEach",o,function(e){function n(){t.updatedAt&&(i=Yn(i,t.updatedAt,r.config.formatUpdated)),r.callHook("afterEach",i,function(e){Gn.call(r,e),a()})}var i;r.isHTML?(i=r.result=o,n()):Vn({compiler:r.compiler,raw:e},function(e){i=r.compiler.compile(e),n()})})},n.prototype._renderCover=function(e,n){var i,o=l(".cover");S(l("main"),n?"add":"remove","hidden"),e?(S(o,"add","show"),(n=(i=this.coverIsHTML?e:this.compiler.cover(e)).trim().match('<p><img.*?data-origin="(.*?)"[^a]+alt="(.*?)">([^<]*?)</p>$'))&&("color"===n[2]?o.style.background=n[1]+(n[3]||""):(e=n[1],S(o,"add","has-mask"),T(n[1])||(e=q(this.router.getBasePath(),n[1])),o.style.backgroundImage="url("+e+")",o.style.backgroundSize="cover",o.style.backgroundPosition="center center"),i=i.replace(n[0],"")),this._renderTo(".cover-main",i),K()):S(o,"remove","show")},n.prototype._updateRender=function(){var e,n,i,o;e=this,n=l(".app-name-link"),i=e.config.nameLink,o=e.route.path,n&&(f(e.config.nameLink)?n.setAttribute("href",i):"object"==typeof i&&(e=Object.keys(i).filter(function(e){return-1<o.indexOf(e)})[0],n.setAttribute("href",i[e])))},n.prototype.initRender=function(){var e=this.config;this.compiler=new In(e,this.router),window.__current_docsify_compiler__=this.compiler;var n,i,o,t,a,r=e.el||"#app",c=b("nav")||w("nav"),u=b(r),f="",p=h;u?(e.repo&&(f+=(t=e.repo,r=e.cornerExternalLinkTarget,t?'<a href="'+(t=(t=!/\/\//.test(t)?"https://github.com/"+t:t).replace(/^git\+/,""))+'" target="'+(r=r||"_blank")+'" class="github-corner" aria-label="View source on Github"><svg viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>':"")),e.coverpage&&(f+=(o=", 100%, 85%",'<section class="cover show" style="background: '+("linear-gradient(to left bottom, hsl("+Math.floor(255*Math.random())+o+") 0%,hsl("+Math.floor(255*Math.random())+o+") 100%)")+'"><div class="mask"></div><div class="cover-main">\x3c!--cover--\x3e</div></section>')),e.logo&&(o=/^data:image/.test(e.logo),n=/(?:http[s]?:)?\/\//.test(e.logo),i=/^\./.test(e.logo),o||n||i||(e.logo=q(this.router.getBasePath(),e.logo))),f+=(i=(n=e).name||"","<main>"+('<button class="sidebar-toggle" aria-label="Menu"><div class="sidebar-toggle-button"><span></span><span></span><span></span></div></button><aside class="sidebar">'+(n.name?'<h1 class="app-name"><a class="app-name-link" data-nosearch>'+(n.logo?'<img alt="'+i+'" src='+n.logo+">":i)+"</a></h1>":"")+'<div class="sidebar-nav">\x3c!--sidebar--\x3e</div></aside>')+'<section class="content"><article class="markdown-section" id="main">\x3c!--main--\x3e</article></section></main>'),this._renderTo(u,f,!0)):this.rendered=!0,e.mergeNavbar&&s?p=b(".sidebar"):(c.classList.add("app-nav"),e.repo||c.classList.add("no-badge")),e.loadNavbar&&y(p,c),e.themeColor&&(v.head.appendChild(w("div","<style>:root{--theme-color: "+e.themeColor+";}</style>").firstElementChild),a=e.themeColor,window.CSS&&window.CSS.supports&&window.CSS.supports("(--v:red)")||(e=k("style:not(.inserted),link"),[].forEach.call(e,function(e){"STYLE"===e.nodeName?Q(e,a):"LINK"===e.nodeName&&(e=e.getAttribute("href"),/\.css$/.test(e)&&X(e).then(function(e){e=w("style",e);_.appendChild(e),Q(e,a)}))}))),this._updateRender(),S(h,"ready")},n}(function(e){function n(){e.apply(this,arguments)}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype.routes=function(){return this.config.routes||{}},n.prototype.matchVirtualRoute=function(t){var a=this.routes(),r=Object.keys(a),c=function(){return null};function u(){var e=r.shift();if(!e)return c(null);var n=A(o=(i="^",0===(o=e).indexOf(i)?o:"^"+o),"$")?o:o+"$",i=t.match(n);if(!i)return u();var o=a[e];if("string"==typeof o)return c(o);if("function"!=typeof o)return u();n=o,e=Xn(),o=e[0];return(0,e[1])(function(e){return"string"==typeof e?c(e):!1===e?c(null):u()}),n.length<=2?o(n(t,i)):n(t,i,o)}return{then:function(e){c=e,u()}}},n}(function(i){function e(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];i.apply(this,e),this.route={}}return i&&(e.__proto__=i),((e.prototype=Object.create(i&&i.prototype)).constructor=e).prototype.updateRender=function(){this.router.normalize(),this.route=this.router.parse(),h.setAttribute("data-page",this.route.file)},e.prototype.initRouter=function(){var n=this,e=this.config,e=new("history"===(e.routerMode||"hash")&&t?D:H)(e);this.router=e,this.updateRender(),U=this.route,e.onchange(function(e){n.updateRender(),n._updateRender(),U.path!==n.route.path?(n.$fetch(d,n.$resetEvents.bind(n,e.source)),U=n.route):n.$resetEvents(e.source)})},e}(function(e){function n(){e.apply(this,arguments)}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype.initLifecycle=function(){var i=this;this._hooks={},this._lifecycle={},["init","mounted","beforeEach","afterEach","doneEach","ready"].forEach(function(e){var n=i._hooks[e]=[];i._lifecycle[e]=function(e){return n.push(e)}})},n.prototype.callHook=function(e,t,a){void 0===a&&(a=d);var r=this._hooks[e],c=this.config.catchPluginErrors,u=function(n){var e=r[n];if(n>=r.length)a(t);else if("function"==typeof e){var i="Docsify plugin error";if(2===e.length)try{e(t,function(e){t=e,u(n+1)})}catch(e){if(!c)throw e;console.error(i,e),u(n+1)}else try{var o=e(t);t=void 0===o?t:o,u(n+1)}catch(e){if(!c)throw e;console.error(i,e),u(n+1)}}else u(n+1)};u(0)},n}(we))))))));function Kn(e,n,i){return Qn&&Qn.abort&&Qn.abort(),Qn=X(e,!0,i)}window.Docsify={util:Me,dom:n,get:X,slugify:Cn,version:"4.13.0"},window.DocsifyCompiler=In,window.marked=Sn,window.Prism=Pn,e(function(e){return new Jn})}(); | ... | ... |
doc/lib/js/search.min.js
0 → 100644
| 1 | +!function(){function u(e){return e.replace(/<!-- {docsify-ignore} -->/,"").replace(/{docsify-ignore}/,"").replace(/<!-- {docsify-ignore-all} -->/,"").replace(/{docsify-ignore-all}/,"").trim()}var f={},m={EXPIRE_KEY:"docsify.search.expires",INDEX_KEY:"docsify.search.index"};function g(e){var n={"&":"&","<":"<",">":">",'"':""","'":"'"};return String(e).replace(/[&<>"']/g,function(e){return n[e]})}function y(e){return e.text||"table"!==e.type||(e.cells.unshift(e.header),e.text=e.cells.map(function(e){return e.join(" | ")}).join(" |\n ")),e.text}function v(e){return e.text||"list"!==e.type||(e.text=e.raw),e.text}function b(o,e,s,c){void 0===e&&(e="");var d,e=window.marked.lexer(e),l=window.Docsify.slugify,p={},h="";return e.forEach(function(e,n){var t,a,i,r;"heading"===e.type&&e.depth<=c?(t=(a=(i=e.text,r={},{str:i=(i=void 0===i?"":i)&&i.replace(/^('|")/,"").replace(/('|")$/,"").replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g,function(e,n,t){return-1===n.indexOf(":")?(r[n]=t&&t.replace(/"/g,"")||!0,""):e}).trim(),config:r})).str,i=a.config,a=u(e.text),d=i.id?s.toURL(o,{id:l(i.id)}):s.toURL(o,{id:l(g(a))}),t&&(h=u(t)),p[d]={slug:d,title:h,body:""}):(0===n&&(d=s.toURL(o),p[d]={slug:d,title:"/"!==o?o.slice(1):"Home Page",body:e.text||""}),d&&(p[d]?p[d].body?(e.text=y(e),e.text=v(e),p[d].body+="\n"+(e.text||"")):(e.text=y(e),e.text=v(e),p[d].body=p[d].body?p[d].body+e.text:e.text):p[d]={slug:d,title:"",body:""}))}),l.clear(),p}function p(e){return e&&e.normalize?e.normalize("NFD").replace(/[\u0300-\u036f]/g,""):e}function o(e){var n=[],t=[];Object.keys(f).forEach(function(n){t=t.concat(Object.keys(f[n]).map(function(e){return f[n][e]}))});var a=(e=e.trim()).split(/[\s\-,\\/]+/);1!==a.length&&(a=[].concat(e,a));for(var i=0;i<t.length;i++)!function(e){var e=t[e],r=0,o="",s="",c="",d=e.title&&e.title.trim(),l=e.body&&e.body.trim(),e=e.slug||"";d&&(a.forEach(function(e){var n,t,a=new RegExp(g(p(e)).replace(/[|\\{}()[\]^$+*?.]/g,"\\$&"),"gi"),i=-1;s=d&&g(p(d)),c=l&&g(p(l)),t=d?s.search(a):-1,i=l?c.search(a):-1,(0<=t||0<=i)&&(r+=0<=t?3:0<=i?2:0,t=(t=n=0)==(n=(i=i<0?0:i)<11?0:i-10)?70:i+e.length+60,l&&t>l.length&&(t=l.length),a=c&&"..."+c.substring(n,t).replace(a,function(e){return'<em class="search-keyword">'+e+"</em>"})+"...",o+=a)}),0<r&&(e={title:s,content:l?o:"",url:e,score:r},n.push(e)))}(i);return n.sort(function(e,n){return n.score-e.score})}function r(a,i){var t,r,n,e,o="auto"===a.paths,s=o?(t=i.router,r=[],Docsify.dom.findAll(".sidebar-nav a:not(.section-link):not([data-nosearch])").forEach(function(e){var n=e.href,e=e.getAttribute("href"),n=t.parse(n).path;n&&-1===r.indexOf(n)&&!Docsify.util.isAbsolutePath(e)&&r.push(n)}),r):a.paths,c="";s.length&&o&&a.pathNamespaces?(n=s[0],Array.isArray(a.pathNamespaces)?c=a.pathNamespaces.filter(function(e){return n.slice(0,e.length)===e})[0]||c:a.pathNamespaces instanceof RegExp&&((d=n.match(a.pathNamespaces))&&(c=d[0])),e=-1===s.indexOf(c+"/"),d=-1===s.indexOf(c+"/README"),e&&d&&s.unshift(c+"/")):-1===s.indexOf("/")&&-1===s.indexOf("/README")&&s.unshift("/");var d,l=((d=a.namespace)?m.EXPIRE_KEY+"/"+d:m.EXPIRE_KEY)+c,p=((d=a.namespace)?m.INDEX_KEY+"/"+d:m.INDEX_KEY)+c,c=localStorage.getItem(l)<Date.now();if(f=JSON.parse(localStorage.getItem(p)),c)f={};else if(!o)return;var h=s.length,u=0;s.forEach(function(t){return f[t]?u++:void Docsify.get(i.router.getFile(t),!1,i.config.requestHeaders).then(function(e){var n;f[t]=b(t,e,i.router,a.depth),h===++u&&(n=a.maxAge,e=p,localStorage.setItem(l,Date.now()+n),localStorage.setItem(e,JSON.stringify(f)))})})}var s,c="";function d(e){var n=Docsify.dom.find("div.search"),t=Docsify.dom.find(n,".results-panel"),a=Docsify.dom.find(n,".clear-button"),i=Docsify.dom.find(".sidebar-nav"),n=Docsify.dom.find(".app-name");if(!e)return t.classList.remove("show"),a.classList.remove("show"),t.innerHTML="",void(s.hideOtherSidebarContent&&(i&&i.classList.remove("hide"),n&&n.classList.remove("hide")));var e=o(e),r="";e.forEach(function(e){r+='<div class="matching-post">\n<a href="'+e.url+'">\n<h2>'+e.title+"</h2>\n<p>"+e.content+"</p>\n</a>\n</div>"}),t.classList.add("show"),a.classList.add("show"),t.innerHTML=r||'<p class="empty">'+c+"</p>",s.hideOtherSidebarContent&&(i&&i.classList.add("hide"),n&&n.classList.add("hide"))}function l(e){s=e}function h(e,n){var t,a,i=n.router.parse().query.s;l(e),Docsify.dom.style("\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0.6em 7px;\n font-size: inherit;\n border: 1px solid transparent;\n}\n\n.search input:focus {\n box-shadow: 0 0 5px var(--theme-color, #42b983);\n border: 1px solid var(--theme-color, #42b983);\n}\n\n.search input::-webkit-search-decoration,\n.search input::-webkit-search-cancel-button,\n.search input {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n.search input::-ms-clear {\n display: none;\n height: 0;\n width: 0;\n}\n\n.search .clear-button {\n cursor: pointer;\n width: 36px;\n text-align: right;\n display: none;\n}\n\n.search .clear-button.show {\n display: block;\n}\n\n.search .clear-button svg {\n transform: scale(.5);\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}\n\n.app-name.hide, .sidebar-nav.hide {\n display: none;\n}"),function(e){void 0===e&&(e="");var n=Docsify.dom.create("div",'<div class="input-wrap">\n <input type="search" value="'+e+'" aria-label="Search text" />\n <div class="clear-button">\n <svg width="26" height="24">\n <circle cx="12" cy="12" r="11" fill="#ccc" />\n <path stroke="white" stroke-width="2" d="M8.25,8.25,15.75,15.75" />\n <path stroke="white" stroke-width="2"d="M8.25,15.75,15.75,8.25" />\n </svg>\n </div>\n </div>\n <div class="results-panel"></div>\n </div>'),e=Docsify.dom.find("aside");Docsify.dom.toggleClass(n,"search"),Docsify.dom.before(e,n)}(i),n=Docsify.dom.find("div.search"),a=Docsify.dom.find(n,"input"),e=Docsify.dom.find(n,".input-wrap"),Docsify.dom.on(n,"click",function(e){return-1===["A","H2","P","EM"].indexOf(e.target.tagName)&&e.stopPropagation()}),Docsify.dom.on(a,"input",function(n){clearTimeout(t),t=setTimeout(function(e){return d(n.target.value.trim())},100)}),Docsify.dom.on(e,"click",function(e){"INPUT"!==e.target.tagName&&(a.value="",d())}),i&&setTimeout(function(e){return d(i)},500)}function x(e,n){var t,a,i,r,o;l(e),t=e.placeholder,a=n.route.path,(r=Docsify.dom.getNode('.search input[type="search"]'))&&("string"==typeof t?r.placeholder=t:(i=Object.keys(t).filter(function(e){return-1<a.indexOf(e)})[0],r.placeholder=t[i])),e=e.noData,o=n.route.path,c="string"==typeof e?e:e[Object.keys(e).filter(function(e){return-1<o.indexOf(e)})[0]]}var w={placeholder:"Type to search",noData:"No Results!",paths:"auto",depth:2,maxAge:864e5,hideOtherSidebarContent:!1,namespace:void 0,pathNamespaces:void 0};$docsify.plugins=[].concat(function(e,n){var t=Docsify.util,a=n.config.search||w;Array.isArray(a)?w.paths=a:"object"==typeof a&&(w.paths=Array.isArray(a.paths)?a.paths:"auto",w.maxAge=(t.isPrimitive(a.maxAge)?a:w).maxAge,w.placeholder=a.placeholder||w.placeholder,w.noData=a.noData||w.noData,w.depth=a.depth||w.depth,w.hideOtherSidebarContent=a.hideOtherSidebarContent||w.hideOtherSidebarContent,w.namespace=a.namespace||w.namespace,w.pathNamespaces=a.pathNamespaces||w.pathNamespaces);var i="auto"===w.paths;e.mounted(function(e){h(w,n),i||r(w,n)}),e.doneEach(function(e){x(w,n),i&&r(w,n)})},$docsify.plugins)}(); | ... | ... |
doc/lib/js/zoom-image.min.js
0 → 100644
| 1 | +!function(){function t(e){return"IMG"===e.tagName}function d(e){function t(){for(var e=arguments,t=arguments.length,o=Array(t),n=0;n<t;n++)o[n]=e[n];var i=o.reduce(function(e,t){return[].concat(e,z(t))},[]);return i.filter(function(e){return-1===m.indexOf(e)}).forEach(function(e){m.push(e),e.classList.add("medium-zoom-image")}),r.forEach(function(e){var t=e.type,o=e.listener,n=e.options;i.forEach(function(e){e.addEventListener(t,o,n)})}),f}function o(){var e=(0<arguments.length&&void 0!==arguments[0]?arguments[0]:{}).target;return s.original?a():i({target:e})}var n=window.Promise||function(e){function t(){}e(t,t)},i=function(){function r(){var e={width:document.documentElement.clientWidth,height:document.documentElement.clientHeight,left:0,top:0,right:0,bottom:0},t=void 0,o=void 0;u.container&&(u.container instanceof Object?(t=(e=g({},e,u.container)).width-e.left-e.right-2*u.margin,o=e.height-e.top-e.bottom-2*u.margin):(r=(i=(h(u.container)?u.container:document.querySelector(u.container)).getBoundingClientRect()).width,m=i.height,d=i.left,a=i.top,e=g({},e,{width:r,height:m,left:d,top:a})));var t=t||e.width-2*u.margin,o=o||e.height-2*u.margin,n=s.zoomedHd||s.original,i=!v(n)&&n.naturalWidth||t,r=!v(n)&&n.naturalHeight||o,d=(m=n.getBoundingClientRect()).top,a=m.left,n=m.width,m=m.height,i=Math.min(i,t)/n,r=Math.min(r,o)/m,r="scale("+(r=Math.min(i,r))+") translate3d("+((t-n)/2-a+u.margin+e.left)/r+"px, "+((o-m)/2-d+u.margin+e.top)/r+"px, 0)";s.zoomed.style.transform=r,s.zoomedHd&&(s.zoomedHd.style.transform=r)}var d=(0<arguments.length&&void 0!==arguments[0]?arguments[0]:{}).target;return new n(function(e){if(d&&-1===m.indexOf(d))e(f);else{function t(){c=!1,s.zoomed.removeEventListener("transitionend",t),s.original.dispatchEvent(E("medium-zoom:opened",{detail:{zoom:f}})),e(f)}var o,n;if(s.zoomed)e(f);else{if(d)s.original=d;else{if(!(0<m.length))return void e(f);var i=m;s.original=i[0]}s.original.dispatchEvent(E("medium-zoom:open",{detail:{zoom:f}})),l=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,c=!0,s.zoomed=b(s.original),document.body.appendChild(p),u.template&&(i=h(u.template)?u.template:document.querySelector(u.template),s.template=document.createElement("div"),s.template.appendChild(i.content.cloneNode(!0)),document.body.appendChild(s.template)),document.body.appendChild(s.zoomed),window.requestAnimationFrame(function(){document.body.classList.add("medium-zoom--opened")}),s.original.classList.add("medium-zoom-image--hidden"),s.zoomed.classList.add("medium-zoom-image--opened"),s.zoomed.addEventListener("click",a),s.zoomed.addEventListener("transitionend",t),s.original.getAttribute("data-zoom-src")?(s.zoomedHd=s.zoomed.cloneNode(),s.zoomedHd.removeAttribute("srcset"),s.zoomedHd.removeAttribute("sizes"),s.zoomedHd.src=s.zoomed.getAttribute("data-zoom-src"),s.zoomedHd.onerror=function(){clearInterval(o),console.warn("Unable to reach the zoom image target "+s.zoomedHd.src),s.zoomedHd=null,r()},o=setInterval(function(){s.zoomedHd.complete&&(clearInterval(o),s.zoomedHd.classList.add("medium-zoom-image--opened"),s.zoomedHd.addEventListener("click",a),document.body.appendChild(s.zoomedHd),r())},10)):s.original.hasAttribute("srcset")?(s.zoomedHd=s.zoomed.cloneNode(),s.zoomedHd.removeAttribute("sizes"),s.zoomedHd.removeAttribute("loading"),n=s.zoomedHd.addEventListener("load",function(){s.zoomedHd.removeEventListener("load",n),s.zoomedHd.classList.add("medium-zoom-image--opened"),s.zoomedHd.addEventListener("click",a),document.body.appendChild(s.zoomedHd),r()})):r()}}})},a=function(){return new n(function(t){var e;!c&&s.original?(e=function e(){s.original.classList.remove("medium-zoom-image--hidden"),document.body.removeChild(s.zoomed),s.zoomedHd&&document.body.removeChild(s.zoomedHd),document.body.removeChild(p),s.zoomed.classList.remove("medium-zoom-image--opened"),s.template&&document.body.removeChild(s.template),c=!1,s.zoomed.removeEventListener("transitionend",e),s.original.dispatchEvent(E("medium-zoom:closed",{detail:{zoom:f}})),s.original=null,s.zoomed=null,s.zoomedHd=null,s.template=null,t(f)},c=!0,document.body.classList.remove("medium-zoom--opened"),s.zoomed.style.transform="",s.zoomedHd&&(s.zoomedHd.style.transform=""),s.template&&(s.template.style.transition="opacity 150ms",s.template.style.opacity=0),s.original.dispatchEvent(E("medium-zoom:close",{detail:{zoom:f}})),s.zoomed.addEventListener("transitionend",e)):t(f)})},m=[],r=[],c=!1,l=0,u=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},s={original:null,zoomed:null,zoomedHd:null,template:null};"[object Object]"===Object.prototype.toString.call(e)?u=e:!e&&"string"!=typeof e||t(e);var u=g({margin:0,background:"#fff",scrollOffset:40,container:null,template:null},u),p=y(u.background);document.addEventListener("click",function(e){e=e.target;e!==p?-1!==m.indexOf(e)&&o({target:e}):a()}),document.addEventListener("keyup",function(e){e=e.key||e.keyCode;"Escape"!==e&&"Esc"!==e&&27!==e||a()}),document.addEventListener("scroll",function(){var e;!c&&s.original&&(e=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,Math.abs(l-e)>u.scrollOffset&&setTimeout(a,150))}),window.addEventListener("resize",a);var f={open:i,close:a,toggle:o,update:function(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},t=e;return e.background&&(p.style.background=e.background),e.container&&e.container instanceof Object&&(t.container=g({},u.container,e.container)),e.template&&(e=h(e.template)?e.template:document.querySelector(e.template),t.template=e),u=g({},u,t),m.forEach(function(e){e.dispatchEvent(E("medium-zoom:update",{detail:{zoom:f}}))}),f},clone:function(){return d(g({},u,0<arguments.length&&void 0!==arguments[0]?arguments[0]:{}))},attach:t,detach:function(){for(var e=arguments,t=arguments.length,o=Array(t),n=0;n<t;n++)o[n]=e[n];s.zoomed&&a();var i=0<o.length?o.reduce(function(e,t){return[].concat(e,z(t))},[]):m;return i.forEach(function(e){e.classList.remove("medium-zoom-image"),e.dispatchEvent(E("medium-zoom:detach",{detail:{zoom:f}}))}),m=m.filter(function(e){return-1===i.indexOf(e)}),f},on:function(t,o){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{};return m.forEach(function(e){e.addEventListener("medium-zoom:"+t,o,n)}),r.push({type:"medium-zoom:"+t,listener:o,options:n}),f},off:function(t,o){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{};return m.forEach(function(e){e.removeEventListener("medium-zoom:"+t,o,n)}),r=r.filter(function(e){return!(e.type==="medium-zoom:"+t&&e.listener.toString()===o.toString())}),f},getOptions:function(){return u},getImages:function(){return m},getZoomedImage:function(){return s.original}};return f}var g=Object.assign||function(e){for(var t=arguments,o=1;o<arguments.length;o++){var n,i=t[o];for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n])}return e},h=function(e){return e&&1===e.nodeType},v=function(e){return".svg"===(e.currentSrc||e.src).substr(-4).toLowerCase()},z=function(e){try{return Array.isArray(e)?e.filter(t):NodeList.prototype.isPrototypeOf(e)?[].slice.call(e).filter(t):h(e)?[e].filter(t):"string"==typeof e?[].slice.call(document.querySelectorAll(e)).filter(t):[]}catch(e){throw new TypeError("The provided selector is invalid.\nExpects a CSS selector, a Node element, a NodeList or an array.\nSee: https://github.com/francoischalifour/medium-zoom")}},y=function(e){var t=document.createElement("div");return t.classList.add("medium-zoom-overlay"),t.style.background=e,t},b=function(e){var t=e.getBoundingClientRect(),o=t.top,n=t.left,i=t.width,r=t.height,d=e.cloneNode(),t=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,e=window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0;return d.removeAttribute("id"),d.style.position="absolute",d.style.top=o+t+"px",d.style.left=n+e+"px",d.style.width=i+"px",d.style.height=r+"px",d.style.transform="",d},E=function(e,t){var o=g({bubbles:!1,cancelable:!1,detail:void 0},t);if("function"==typeof window.CustomEvent)return new CustomEvent(e,o);t=document.createEvent("CustomEvent");return t.initCustomEvent(e,o.bubbles,o.cancelable,o.detail),t};var e,o,n,i;e=".medium-zoom-overlay{position:fixed;top:0;right:0;bottom:0;left:0;opacity:0;transition:opacity .3s;will-change:opacity}.medium-zoom--opened .medium-zoom-overlay{cursor:pointer;cursor:zoom-out;opacity:1}.medium-zoom-image{cursor:pointer;cursor:zoom-in;transition:transform .3s cubic-bezier(.2,0,.2,1)!important}.medium-zoom-image--hidden{visibility:hidden}.medium-zoom-image--opened{position:relative;cursor:pointer;cursor:zoom-out;will-change:transform}",i=(o=void 0===o?{}:o).insertAt,e&&"undefined"!=typeof document&&(n=document.head||document.getElementsByTagName("head")[0],(o=document.createElement("style")).type="text/css","top"===i&&n.firstChild?n.insertBefore(o,n.firstChild):n.appendChild(o),o.styleSheet?o.styleSheet.cssText=e:o.appendChild(document.createTextNode(e)));var r=Element.prototype.matches||Element.prototype.webkitMatchesSelector||Element.prototype.msMatchesSelector;$docsify.plugins=[].concat(function(e){var o;e.doneEach(function(e){var t=(t=Array.apply(null,document.querySelectorAll(".markdown-section img:not(.emoji):not([data-no-zoom])"))).filter(function(e){return!1===r.call(e,"a img")});o&&o.detach(),o=d(t)})},$docsify.plugins)}(); | ... | ... |
libs/jdbc-aarch/kingbase8-8.6.0.jar
0 → 100644
No preview for this file type
libs/jdbc-aarch/kingbase8-8.6.0.jre7.jar
0 → 100644
No preview for this file type
libs/jdbc-aarch/postgresql-42.2.9.jar
0 → 100644
No preview for this file type
libs/jdbc-aarch/postgresql-42.2.9.jre7.jar
0 → 100644
No preview for this file type
pom.xml
| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | |
| 12 | 12 | <groupId>com.genersoft</groupId> |
| 13 | 13 | <artifactId>wvp-pro</artifactId> |
| 14 | - <version>2.6.8</version> | |
| 14 | + <version>2.6.9</version> | |
| 15 | 15 | <name>web video platform</name> |
| 16 | 16 | <description>国标28181视频平台</description> |
| 17 | 17 | <packaging>${project.packaging}</packaging> |
| ... | ... | @@ -135,11 +135,30 @@ |
| 135 | 135 | <version>8.0.30</version> |
| 136 | 136 | </dependency> |
| 137 | 137 | |
| 138 | + <!--postgresql--> | |
| 139 | + <dependency> | |
| 140 | + <groupId>org.postgresql</groupId> | |
| 141 | + <artifactId>postgresql</artifactId> | |
| 142 | + <version>42.5.1</version> | |
| 143 | + </dependency> | |
| 144 | + | |
| 145 | + <!-- kingbase人大金仓 --> | |
| 146 | + <!-- 手动下载驱动后安装 --> | |
| 147 | + <!-- mvn install:install-file -Dfile=/home/lin/soft/kingbase/jdbc-aarch/kingbase8-8.6.0.jar -DgroupId=com.kingbase -DartifactId=kingbase8 -Dversion=8.6.0 -Dpackaging=jar | |
| 148 | + --> | |
| 149 | + <dependency> | |
| 150 | + <groupId>com.kingbase</groupId> | |
| 151 | + <artifactId>kingbase8</artifactId> | |
| 152 | + <version>8.6.0</version> | |
| 153 | + <scope>system</scope> | |
| 154 | + <systemPath>${basedir}/libs/jdbc-aarch/kingbase8-8.6.0.jar</systemPath> | |
| 155 | + </dependency> | |
| 156 | + | |
| 138 | 157 | <!--Mybatis分页插件 --> |
| 139 | 158 | <dependency> |
| 140 | 159 | <groupId>com.github.pagehelper</groupId> |
| 141 | 160 | <artifactId>pagehelper-spring-boot-starter</artifactId> |
| 142 | - <version>1.4.3</version> | |
| 161 | + <version>1.4.6</version> | |
| 143 | 162 | </dependency> |
| 144 | 163 | |
| 145 | 164 | <!--在线文档 --> | ... | ... |
sql/2.6.6-2.6.7更新.sql
| ... | ... | @@ -7,6 +7,7 @@ alter table parent_platform |
| 7 | 7 | alter table device |
| 8 | 8 | add mediaServerId varchar(50) default null; |
| 9 | 9 | |
| 10 | - | |
| 10 | +ALTER TABLE device | |
| 11 | + ADD COLUMN `switchPrimarySubStream` bit(1) NOT NULL DEFAULT b'0' COMMENT '开启主子码流切换的开关(0-不开启,1-开启)现在已知支持设备为 大华、TP——LINK全系设备' AFTER `keepalive_interval_time` | |
| 11 | 12 | |
| 12 | 13 | ... | ... |
sql/2.6.8升级2.6.9.sql
0 → 100644
| 1 | +alter table device | |
| 2 | + change deviceId device_id varchar(50) not null; | |
| 3 | + | |
| 4 | +alter table device | |
| 5 | + change streamMode stream_mode varchar(50) null; | |
| 6 | + | |
| 7 | +alter table device | |
| 8 | + change registerTime register_time varchar(50) null; | |
| 9 | + | |
| 10 | +alter table device | |
| 11 | + change keepaliveTime keepalive_time varchar(50) null; | |
| 12 | + | |
| 13 | +alter table device | |
| 14 | + change createTime create_time varchar(50) not null; | |
| 15 | + | |
| 16 | +alter table device | |
| 17 | + change updateTime update_time varchar(50) not null; | |
| 18 | + | |
| 19 | +alter table device | |
| 20 | + change subscribeCycleForCatalog subscribe_cycle_for_catalog bool default false; | |
| 21 | + | |
| 22 | +alter table device | |
| 23 | + change subscribeCycleForMobilePosition subscribe_cycle_for_mobile_position bool default false; | |
| 24 | + | |
| 25 | +alter table device | |
| 26 | + change mobilePositionSubmissionInterval mobile_position_submission_interval int default 5 not null; | |
| 27 | + | |
| 28 | +alter table device | |
| 29 | + change subscribeCycleForAlarm subscribe_cycle_for_alarm bool default false; | |
| 30 | + | |
| 31 | +alter table device | |
| 32 | + change hostAddress host_address varchar(50) null; | |
| 33 | + | |
| 34 | +alter table device | |
| 35 | + change ssrcCheck ssrc_check bool default false; | |
| 36 | + | |
| 37 | +alter table device | |
| 38 | + change geoCoordSys geo_coord_sys varchar(50) not null; | |
| 39 | + | |
| 40 | +alter table device | |
| 41 | + drop column treeType; | |
| 42 | + | |
| 43 | +alter table device | |
| 44 | + change mediaServerId media_server_id varchar(50) default 'auto' null; | |
| 45 | + | |
| 46 | +alter table device | |
| 47 | + change sdpIp sdp_ip varchar(50) null; | |
| 48 | + | |
| 49 | +alter table device | |
| 50 | + change localIp local_ip varchar(50) null; | |
| 51 | + | |
| 52 | +alter table device | |
| 53 | + change asMessageChannel as_message_channel bool default false; | |
| 54 | + | |
| 55 | +alter table device | |
| 56 | + change keepaliveIntervalTime keepalive_interval_time int null; | |
| 57 | + | |
| 58 | +alter table device | |
| 59 | + change online on_line varchar(50) null; | |
| 60 | + | |
| 61 | +alter table device | |
| 62 | + add COLUMN switch_primary_sub_stream bool default false comment '开启主子码流切换的开关(0-不开启,1-开启)现在已知支持设备为 大华、TP——LINK全系设备' | |
| 63 | + | |
| 64 | + | |
| 65 | +alter table device_alarm | |
| 66 | + change deviceId device_id varchar(50) not null; | |
| 67 | + | |
| 68 | +alter table device_alarm | |
| 69 | + change channelId channel_id varchar(50) not null; | |
| 70 | + | |
| 71 | +alter table device_alarm | |
| 72 | + change alarmPriority alarm_priority varchar(50) not null; | |
| 73 | + | |
| 74 | +alter table device_alarm | |
| 75 | + change alarmMethod alarm_method varchar(50) null; | |
| 76 | + | |
| 77 | +alter table device_alarm | |
| 78 | + change alarmTime alarm_time varchar(50) not null; | |
| 79 | + | |
| 80 | +alter table device_alarm | |
| 81 | + change alarmDescription alarm_description varchar(255) null; | |
| 82 | + | |
| 83 | +alter table device_alarm | |
| 84 | + change alarmType alarm_type varchar(50) null; | |
| 85 | + | |
| 86 | +alter table device_alarm | |
| 87 | + change createTime create_time varchar(50) null; | |
| 88 | + | |
| 89 | +alter table device_channel | |
| 90 | + change channelId channel_id varchar(50) not null; | |
| 91 | + | |
| 92 | +alter table device_channel | |
| 93 | + change civilCode civil_code varchar(50) null; | |
| 94 | + | |
| 95 | +alter table device_channel | |
| 96 | + change parentId parent_id varchar(50) null; | |
| 97 | + | |
| 98 | +alter table device_channel | |
| 99 | + change safetyWay safety_way int null; | |
| 100 | + | |
| 101 | +alter table device_channel | |
| 102 | + change registerWay register_way int null; | |
| 103 | + | |
| 104 | +alter table device_channel | |
| 105 | + change certNum cert_num varchar(50) null; | |
| 106 | + | |
| 107 | +alter table device_channel | |
| 108 | + change errCode err_code int null; | |
| 109 | + | |
| 110 | +alter table device_channel | |
| 111 | + change endTime end_time varchar(50) null; | |
| 112 | + | |
| 113 | +alter table device_channel | |
| 114 | + change ipAddress ip_address varchar(50) null; | |
| 115 | + | |
| 116 | +alter table device_channel | |
| 117 | + change PTZType ptz_type int null; | |
| 118 | + | |
| 119 | +alter table device_channel | |
| 120 | + change status status bool default false; | |
| 121 | + | |
| 122 | +alter table device_channel | |
| 123 | + change streamId stream_id varchar(50) null; | |
| 124 | + | |
| 125 | +alter table device_channel | |
| 126 | + change deviceId device_id varchar(50) not null; | |
| 127 | + | |
| 128 | + | |
| 129 | +alter table device_channel | |
| 130 | + change hasAudio has_audio bool default false; | |
| 131 | + | |
| 132 | +alter table device_channel | |
| 133 | + change createTime create_time varchar(50) not null; | |
| 134 | + | |
| 135 | +alter table device_channel | |
| 136 | + change updateTime update_time varchar(50) not null; | |
| 137 | + | |
| 138 | +alter table device_channel | |
| 139 | + change subCount sub_count int default 0 null; | |
| 140 | + | |
| 141 | +alter table device_channel | |
| 142 | + change longitudeGcj02 longitude_gcj02 double null; | |
| 143 | + | |
| 144 | +alter table device_channel | |
| 145 | + change latitudeGcj02 latitude_gcj02 double null; | |
| 146 | + | |
| 147 | +alter table device_channel | |
| 148 | + change longitudeWgs84 longitude_wgs84 double null; | |
| 149 | + | |
| 150 | +alter table device_channel | |
| 151 | + change latitudeWgs84 latitude_wgs84 double null; | |
| 152 | + | |
| 153 | +alter table device_channel | |
| 154 | + change businessGroupId business_group_id varchar(50) null; | |
| 155 | + | |
| 156 | +alter table device_channel | |
| 157 | + change gpsTime gps_time varchar(50) null; | |
| 158 | + | |
| 159 | +alter table device_mobile_position | |
| 160 | + change deviceId device_id varchar(50) not null; | |
| 161 | + | |
| 162 | +alter table device_mobile_position | |
| 163 | + change channelId channel_id varchar(50) not null; | |
| 164 | + | |
| 165 | +alter table device_mobile_position | |
| 166 | + change deviceName device_name varchar(255) null; | |
| 167 | + | |
| 168 | +alter table device_mobile_position | |
| 169 | + change reportSource report_source varchar(50) null; | |
| 170 | + | |
| 171 | +alter table device_mobile_position | |
| 172 | + change longitudeGcj02 longitude_gcj02 double null; | |
| 173 | + | |
| 174 | +alter table device_mobile_position | |
| 175 | + change latitudeGcj02 latitude_gcj02 double null; | |
| 176 | + | |
| 177 | +alter table device_mobile_position | |
| 178 | + change longitudeWgs84 longitude_wgs84 double null; | |
| 179 | + | |
| 180 | +alter table device_mobile_position | |
| 181 | + change latitudeWgs84 latitude_wgs84 double null; | |
| 182 | + | |
| 183 | +alter table device_mobile_position | |
| 184 | + change createTime create_time varchar(50) null; | |
| 185 | + | |
| 186 | +alter table gb_stream | |
| 187 | + change gbStreamId gb_stream_id int auto_increment; | |
| 188 | + | |
| 189 | +alter table gb_stream | |
| 190 | + change gbId gb_id varchar(50) not null; | |
| 191 | + | |
| 192 | +alter table gb_stream | |
| 193 | + change streamType stream_type varchar(50) null; | |
| 194 | + | |
| 195 | +alter table gb_stream | |
| 196 | + change mediaServerId media_server_id varchar(50) null; | |
| 197 | + | |
| 198 | +alter table gb_stream | |
| 199 | + change createTime create_time varchar(50) null; | |
| 200 | + | |
| 201 | +alter table log | |
| 202 | + change createTime create_time varchar(50) not null; | |
| 203 | + | |
| 204 | +alter table media_server | |
| 205 | + change hookIp hook_ip varchar(50) not null; | |
| 206 | + | |
| 207 | +alter table media_server | |
| 208 | + change sdpIp sdp_ip varchar(50) not null; | |
| 209 | + | |
| 210 | +alter table media_server | |
| 211 | + change streamIp stream_ip varchar(50) not null; | |
| 212 | + | |
| 213 | +alter table media_server | |
| 214 | + change httpPort http_port int not null; | |
| 215 | + | |
| 216 | +alter table media_server | |
| 217 | + change httpSSlPort http_ssl_port int not null; | |
| 218 | + | |
| 219 | +alter table media_server | |
| 220 | + change rtmpPort rtmp_port int not null; | |
| 221 | + | |
| 222 | +alter table media_server | |
| 223 | + change rtmpSSlPort rtmp_ssl_port int not null; | |
| 224 | + | |
| 225 | +alter table media_server | |
| 226 | + change rtpProxyPort rtp_proxy_port int not null; | |
| 227 | + | |
| 228 | +alter table media_server | |
| 229 | + change rtspPort rtsp_port int not null; | |
| 230 | + | |
| 231 | +alter table media_server | |
| 232 | + change rtspSSLPort rtsp_ssl_port int not null; | |
| 233 | + | |
| 234 | +alter table media_server | |
| 235 | + change autoConfig auto_config bool default true; | |
| 236 | + | |
| 237 | +alter table media_server | |
| 238 | + change rtpEnable rtp_enable bool default false; | |
| 239 | + | |
| 240 | +alter table media_server | |
| 241 | + change rtpPortRange rtp_port_range varchar(50) not null; | |
| 242 | + | |
| 243 | +alter table media_server | |
| 244 | + change recordAssistPort record_assist_port int not null; | |
| 245 | + | |
| 246 | +alter table media_server | |
| 247 | + change defaultServer default_server bool default false; | |
| 248 | + | |
| 249 | +alter table media_server | |
| 250 | + change createTime create_time varchar(50) not null; | |
| 251 | + | |
| 252 | +alter table media_server | |
| 253 | + change updateTime update_time varchar(50) not null; | |
| 254 | + | |
| 255 | +alter table media_server | |
| 256 | + change hookAliveInterval hook_alive_interval int not null; | |
| 257 | + | |
| 258 | +alter table parent_platform | |
| 259 | + change serverGBId server_gb_id varchar(50) not null; | |
| 260 | + | |
| 261 | +alter table parent_platform | |
| 262 | + change serverGBDomain server_gb_domain varchar(50) null; | |
| 263 | + | |
| 264 | +alter table parent_platform | |
| 265 | + change serverIP server_ip varchar(50) null; | |
| 266 | + | |
| 267 | +alter table parent_platform | |
| 268 | + change serverPort server_port int null; | |
| 269 | + | |
| 270 | +alter table parent_platform | |
| 271 | + change deviceGBId device_gb_id varchar(50) not null; | |
| 272 | + | |
| 273 | +alter table parent_platform | |
| 274 | + change deviceIp device_ip varchar(50) null; | |
| 275 | + | |
| 276 | +alter table parent_platform | |
| 277 | + change devicePort device_port varchar(50) null; | |
| 278 | + | |
| 279 | +alter table parent_platform | |
| 280 | + change keepTimeout keep_timeout varchar(50) null; | |
| 281 | + | |
| 282 | +alter table parent_platform | |
| 283 | + change characterSet character_set varchar(50) null; | |
| 284 | + | |
| 285 | +alter table parent_platform | |
| 286 | + change catalogId catalog_id varchar(50) not null; | |
| 287 | + | |
| 288 | +alter table parent_platform | |
| 289 | + change startOfflinePush start_offline_push bool default false; | |
| 290 | + | |
| 291 | +alter table parent_platform | |
| 292 | + change administrativeDivision administrative_division varchar(50) not null; | |
| 293 | + | |
| 294 | +alter table parent_platform | |
| 295 | + change catalogGroup catalog_group int default 1 null; | |
| 296 | + | |
| 297 | +alter table parent_platform | |
| 298 | + change createTime create_time varchar(50) null; | |
| 299 | + | |
| 300 | +alter table parent_platform | |
| 301 | + change updateTime update_time varchar(50) null; | |
| 302 | + | |
| 303 | +alter table parent_platform | |
| 304 | + drop column treeType; | |
| 305 | + | |
| 306 | +alter table parent_platform | |
| 307 | + change asMessageChannel as_message_channel bool default false; | |
| 308 | + | |
| 309 | +alter table parent_platform | |
| 310 | + change enable enable bool default false; | |
| 311 | + | |
| 312 | +alter table parent_platform | |
| 313 | + change ptz ptz bool default false; | |
| 314 | + | |
| 315 | +alter table parent_platform | |
| 316 | + change rtcp rtcp bool default false; | |
| 317 | + | |
| 318 | +alter table parent_platform | |
| 319 | + change status status bool default false; | |
| 320 | + | |
| 321 | +alter table parent_platform | |
| 322 | + change status status bool default false; | |
| 323 | + | |
| 324 | +alter table platform_catalog | |
| 325 | + change platformId platform_id varchar(50) not null; | |
| 326 | + | |
| 327 | +alter table platform_catalog | |
| 328 | + change parentId parent_id varchar(50) null; | |
| 329 | + | |
| 330 | +alter table platform_catalog | |
| 331 | + change civilCode civil_code varchar(50) null; | |
| 332 | + | |
| 333 | +alter table platform_catalog | |
| 334 | + change businessGroupId business_group_id varchar(50) null; | |
| 335 | + | |
| 336 | +alter table platform_gb_channel | |
| 337 | + change platformId platform_id varchar(50) not null; | |
| 338 | + | |
| 339 | +alter table platform_gb_channel | |
| 340 | + change catalogId catalog_id varchar(50) not null; | |
| 341 | + | |
| 342 | +alter table platform_gb_channel | |
| 343 | + change deviceChannelId device_channel_id int not null; | |
| 344 | + | |
| 345 | +alter table platform_gb_stream | |
| 346 | + change platformId platform_id varchar(50) not null; | |
| 347 | + | |
| 348 | +alter table platform_gb_stream | |
| 349 | + change catalogId catalog_id varchar(50) not null; | |
| 350 | + | |
| 351 | +alter table platform_gb_stream | |
| 352 | + change gbStreamId gb_stream_id int not null; | |
| 353 | + | |
| 354 | +alter table stream_proxy | |
| 355 | + change mediaServerId media_server_id varchar(50) null; | |
| 356 | + | |
| 357 | +alter table stream_proxy | |
| 358 | + change createTime create_time varchar(50) not null; | |
| 359 | + | |
| 360 | +alter table stream_proxy | |
| 361 | + change updateTime update_time varchar(50) null; | |
| 362 | + | |
| 363 | +alter table stream_proxy | |
| 364 | + change enable_remove_none_reader enable_remove_none_reader bool default false; | |
| 365 | + | |
| 366 | +alter table stream_proxy | |
| 367 | + change enable_disable_none_reader enable_disable_none_reader bool default false; | |
| 368 | + | |
| 369 | +alter table stream_proxy | |
| 370 | + change enable_audio enable_audio bool default false; | |
| 371 | + | |
| 372 | +alter table stream_proxy | |
| 373 | + change enable_mp4 enable_mp4 bool default false; | |
| 374 | + | |
| 375 | +alter table stream_proxy | |
| 376 | + change enable enable bool default false; | |
| 377 | + | |
| 378 | +alter table stream_push | |
| 379 | + change totalReaderCount total_reader_count varchar(50) null; | |
| 380 | + | |
| 381 | +alter table stream_push | |
| 382 | + change originType origin_type int null; | |
| 383 | + | |
| 384 | +alter table stream_push | |
| 385 | + change originTypeStr origin_type_str varchar(50) null; | |
| 386 | + | |
| 387 | +alter table stream_push | |
| 388 | + change createTime create_time varchar(50) null; | |
| 389 | + | |
| 390 | +alter table stream_push | |
| 391 | + change aliveSecond alive_second int null; | |
| 392 | + | |
| 393 | +alter table stream_push | |
| 394 | + change mediaServerId media_server_id varchar(50) null; | |
| 395 | + | |
| 396 | +alter table stream_push | |
| 397 | + change status status bool default false; | |
| 398 | + | |
| 399 | +alter table stream_push | |
| 400 | + change pushTime push_time varchar(50) null; | |
| 401 | + | |
| 402 | +alter table stream_push | |
| 403 | + change updateTime update_time varchar(50) null; | |
| 404 | + | |
| 405 | +alter table stream_push | |
| 406 | + change pushIng push_ing bool default false; | |
| 407 | + | |
| 408 | +alter table stream_push | |
| 409 | + change status status bool default false; | |
| 410 | + | |
| 411 | +alter table stream_push | |
| 412 | + change self self bool default false; | |
| 413 | + | |
| 414 | +alter table stream_push | |
| 415 | + drop column serverId; | |
| 416 | + | |
| 417 | + | |
| 418 | +alter table user | |
| 419 | + change roleId role_id int not null; | |
| 420 | + | |
| 421 | +alter table user | |
| 422 | + change createTime create_time varchar(50) not null; | |
| 423 | + | |
| 424 | +alter table user | |
| 425 | + change updateTime update_time varchar(50) not null; | |
| 426 | + | |
| 427 | +alter table user | |
| 428 | + change pushKey push_key varchar(50) null; | |
| 429 | + | |
| 430 | +alter table user_role | |
| 431 | + change createTime create_time varchar(50) not null; | |
| 432 | + | |
| 433 | +alter table user_role | |
| 434 | + change updateTime update_time varchar(50) not null; | |
| 435 | + | |
| 436 | +rename table device to wvp_device; | |
| 437 | +rename table device_alarm to wvp_device_alarm; | |
| 438 | +rename table device_channel to wvp_device_channel; | |
| 439 | +rename table device_mobile_position to wvp_device_mobile_position; | |
| 440 | +rename table gb_stream to wvp_gb_stream; | |
| 441 | +rename table log to wvp_log; | |
| 442 | +rename table media_server to wvp_media_server; | |
| 443 | +rename table parent_platform to wvp_platform; | |
| 444 | +rename table platform_catalog to wvp_platform_catalog; | |
| 445 | +rename table platform_gb_channel to wvp_platform_gb_channel; | |
| 446 | +rename table platform_gb_stream to wvp_platform_gb_stream; | |
| 447 | +rename table stream_proxy to wvp_stream_proxy; | |
| 448 | +rename table stream_push to wvp_stream_push; | |
| 449 | +rename table user to wvp_user; | |
| 450 | +rename table user_role to wvp_user_role; | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | ... | ... |
sql/clean.sql
| 1 | -delete from device; | |
| 2 | -delete from device_alarm; | |
| 3 | -delete from device_channel; | |
| 4 | -delete from device_mobile_position; | |
| 5 | -delete from gb_stream; | |
| 6 | -delete from log; | |
| 7 | -delete from media_server; | |
| 8 | -delete from parent_platform; | |
| 9 | -delete from platform_catalog; | |
| 10 | -delete from platform_gb_channel; | |
| 11 | -delete from platform_gb_stream; | |
| 12 | -delete from stream_proxy; | |
| 13 | -delete from stream_push; | |
| 14 | 1 | \ No newline at end of file |
| 2 | +delete from wvp-device; | |
| 3 | +delete from wvp-device_alarm; | |
| 4 | +delete from wvp-device_channel; | |
| 5 | +delete from wvp-device_mobile_position; | |
| 6 | +delete from wvp-gb_stream; | |
| 7 | +delete from wvp-log; | |
| 8 | +delete from wvp-media_server; | |
| 9 | +delete from wvp-parent_platform; | |
| 10 | +delete from wvp-platform_catalog; | |
| 11 | +delete from wvp-platform_gb_channel; | |
| 12 | +delete from wvp-platform_gb_stream; | |
| 13 | +delete from wvp-stream_proxy; | |
| 14 | +delete from wvp-stream_push; | |
| 15 | 15 | \ No newline at end of file | ... | ... |
sql/初始化.sql
| 1 | --- MySQL dump 10.13 Distrib 8.0.31, for Linux (x86_64) | |
| 2 | --- | |
| 3 | --- Host: 127.0.0.1 Database: wvp | |
| 4 | --- ------------------------------------------------------ | |
| 5 | --- Server version 8.0.30 | |
| 1 | +/*建表*/ | |
| 2 | +create table wvp_device ( | |
| 3 | + id serial primary key , | |
| 4 | + device_id character varying(50) not null , | |
| 5 | + name character varying(255), | |
| 6 | + manufacturer character varying(255), | |
| 7 | + model character varying(255), | |
| 8 | + firmware character varying(255), | |
| 9 | + transport character varying(50), | |
| 10 | + stream_mode character varying(50), | |
| 11 | + on_line bool default false, | |
| 12 | + register_time character varying(50), | |
| 13 | + keepalive_time character varying(50), | |
| 14 | + ip character varying(50), | |
| 15 | + create_time character varying(50), | |
| 16 | + update_time character varying(50), | |
| 17 | + port integer, | |
| 18 | + expires integer, | |
| 19 | + subscribe_cycle_for_catalog integer DEFAULT 0, | |
| 20 | + subscribe_cycle_for_mobile_position integer DEFAULT 0, | |
| 21 | + mobile_position_submission_interval integer DEFAULT 5, | |
| 22 | + subscribe_cycle_for_alarm integer DEFAULT 0, | |
| 23 | + host_address character varying(50), | |
| 24 | + charset character varying(50), | |
| 25 | + ssrc_check bool default false, | |
| 26 | + geo_coord_sys character varying(50), | |
| 27 | + media_server_id character varying(50), | |
| 28 | + custom_name character varying(255), | |
| 29 | + sdp_ip character varying(50), | |
| 30 | + local_ip character varying(50), | |
| 31 | + password character varying(255), | |
| 32 | + as_message_channel bool default false, | |
| 33 | + keepalive_interval_time integer, | |
| 34 | + switch_primary_sub_stream bool default false, | |
| 35 | + constraint uk_device_device unique (device_id) | |
| 36 | +); | |
| 37 | + | |
| 38 | +create table wvp_device_alarm ( | |
| 39 | + id serial primary key , | |
| 40 | + device_id character varying(50) not null, | |
| 41 | + channel_id character varying(50) not null, | |
| 42 | + alarm_priority character varying(50), | |
| 43 | + alarm_method character varying(50), | |
| 44 | + alarm_time character varying(50), | |
| 45 | + alarm_description character varying(255), | |
| 46 | + longitude double precision, | |
| 47 | + latitude double precision, | |
| 48 | + alarm_type character varying(50), | |
| 49 | + create_time character varying(50) not null | |
| 50 | +); | |
| 51 | + | |
| 52 | +create table wvp_device_channel ( | |
| 53 | + id serial primary key , | |
| 54 | + channel_id character varying(50) not null, | |
| 55 | + name character varying(255), | |
| 56 | + manufacture character varying(50), | |
| 57 | + model character varying(50), | |
| 58 | + owner character varying(50), | |
| 59 | + civil_code character varying(50), | |
| 60 | + block character varying(50), | |
| 61 | + address character varying(50), | |
| 62 | + parent_id character varying(50), | |
| 63 | + safety_way integer, | |
| 64 | + register_way integer, | |
| 65 | + cert_num character varying(50), | |
| 66 | + certifiable integer, | |
| 67 | + err_code integer, | |
| 68 | + end_time character varying(50), | |
| 69 | + secrecy character varying(50), | |
| 70 | + ip_address character varying(50), | |
| 71 | + port integer, | |
| 72 | + password character varying(255), | |
| 73 | + ptz_type integer, | |
| 74 | + status bool default false, | |
| 75 | + longitude double precision, | |
| 76 | + latitude double precision, | |
| 77 | + stream_id character varying(50), | |
| 78 | + device_id character varying(50) not null, | |
| 79 | + parental character varying(50), | |
| 80 | + has_audio bool default false, | |
| 81 | + create_time character varying(50) not null, | |
| 82 | + update_time character varying(50) not null, | |
| 83 | + sub_count integer, | |
| 84 | + longitude_gcj02 double precision, | |
| 85 | + latitude_gcj02 double precision, | |
| 86 | + longitude_wgs84 double precision, | |
| 87 | + latitude_wgs84 double precision, | |
| 88 | + business_group_id character varying(50), | |
| 89 | + gps_time character varying(50), | |
| 90 | + constraint uk_wvp_device_channel_unique_device_channel unique (device_id, channel_id) | |
| 91 | +); | |
| 92 | + | |
| 93 | +create table wvp_device_mobile_position ( | |
| 94 | + id serial primary key, | |
| 95 | + device_id character varying(50) not null, | |
| 96 | + channel_id character varying(50) not null, | |
| 97 | + device_name character varying(255), | |
| 98 | + time character varying(50), | |
| 99 | + longitude double precision, | |
| 100 | + latitude double precision, | |
| 101 | + altitude double precision, | |
| 102 | + speed double precision, | |
| 103 | + direction double precision, | |
| 104 | + report_source character varying(50), | |
| 105 | + longitude_gcj02 double precision, | |
| 106 | + latitude_gcj02 double precision, | |
| 107 | + longitude_wgs84 double precision, | |
| 108 | + latitude_wgs84 double precision, | |
| 109 | + create_time character varying(50) | |
| 110 | +); | |
| 111 | + | |
| 112 | +create table wvp_gb_stream ( | |
| 113 | + gb_stream_id serial primary key, | |
| 114 | + app character varying(255) not null, | |
| 115 | + stream character varying(255) not null, | |
| 116 | + gb_id character varying(50) not null, | |
| 117 | + name character varying(255), | |
| 118 | + longitude double precision, | |
| 119 | + latitude double precision, | |
| 120 | + stream_type character varying(50), | |
| 121 | + media_server_id character varying(50), | |
| 122 | + create_time character varying(50), | |
| 123 | + constraint uk_gb_stream_unique_gb_id unique (gb_id), | |
| 124 | + constraint uk_gb_stream_unique_app_stream unique (app, stream) | |
| 125 | +); | |
| 126 | + | |
| 127 | +create table wvp_log ( | |
| 128 | + id serial primary key , | |
| 129 | + name character varying(50), | |
| 130 | + type character varying(50), | |
| 131 | + uri character varying(200), | |
| 132 | + address character varying(50), | |
| 133 | + result character varying(50), | |
| 134 | + timing bigint, | |
| 135 | + username character varying(50), | |
| 136 | + create_time character varying(50) | |
| 137 | +); | |
| 138 | + | |
| 139 | +create table wvp_media_server ( | |
| 140 | + id character varying(255) primary key , | |
| 141 | + ip character varying(50), | |
| 142 | + hook_ip character varying(50), | |
| 143 | + sdp_ip character varying(50), | |
| 144 | + stream_ip character varying(50), | |
| 145 | + http_port integer, | |
| 146 | + http_ssl_port integer, | |
| 147 | + rtmp_port integer, | |
| 148 | + rtmp_ssl_port integer, | |
| 149 | + rtp_proxy_port integer, | |
| 150 | + rtsp_port integer, | |
| 151 | + rtsp_ssl_port integer, | |
| 152 | + auto_config bool default false, | |
| 153 | + secret character varying(50), | |
| 154 | + rtp_enable bool default false, | |
| 155 | + rtp_port_range character varying(50), | |
| 156 | + record_assist_port integer, | |
| 157 | + default_server bool default false, | |
| 158 | + create_time character varying(50), | |
| 159 | + update_time character varying(50), | |
| 160 | + hook_alive_interval integer, | |
| 161 | + constraint uk_media_server_unique_ip_http_port unique (ip, http_port) | |
| 162 | +); | |
| 163 | + | |
| 164 | +create table wvp_platform ( | |
| 165 | + id serial primary key , | |
| 166 | + enable bool default false, | |
| 167 | + name character varying(255), | |
| 168 | + server_gb_id character varying(50), | |
| 169 | + server_gb_domain character varying(50), | |
| 170 | + server_ip character varying(50), | |
| 171 | + server_port integer, | |
| 172 | + device_gb_id character varying(50), | |
| 173 | + device_ip character varying(50), | |
| 174 | + device_port character varying(50), | |
| 175 | + username character varying(255), | |
| 176 | + password character varying(50), | |
| 177 | + expires character varying(50), | |
| 178 | + keep_timeout character varying(50), | |
| 179 | + transport character varying(50), | |
| 180 | + character_set character varying(50), | |
| 181 | + catalog_id character varying(50), | |
| 182 | + ptz bool default false, | |
| 183 | + rtcp bool default false, | |
| 184 | + status bool default false, | |
| 185 | + start_offline_push bool default false, | |
| 186 | + administrative_division character varying(50), | |
| 187 | + catalog_group integer, | |
| 188 | + create_time character varying(50), | |
| 189 | + update_time character varying(50), | |
| 190 | + as_message_channel bool default false, | |
| 191 | + constraint uk_platform_unique_server_gb_id unique (server_gb_id) | |
| 192 | +); | |
| 193 | + | |
| 194 | +create table wvp_platform_catalog ( | |
| 195 | + id character varying(50), | |
| 196 | + platform_id character varying(50), | |
| 197 | + name character varying(255), | |
| 198 | + parent_id character varying(50), | |
| 199 | + civil_code character varying(50), | |
| 200 | + business_group_id character varying(50), | |
| 201 | + constraint uk_platform_catalog_id_platform_id unique (id, platform_id) | |
| 202 | +); | |
| 203 | + | |
| 204 | +create table wvp_platform_gb_channel ( | |
| 205 | + id serial primary key , | |
| 206 | + platform_id character varying(50), | |
| 207 | + catalog_id character varying(50), | |
| 208 | + device_channel_id integer, | |
| 209 | + constraint uk_platform_gb_channel_platform_id_catalog_id_device_channel_id unique (platform_id, catalog_id, device_channel_id) | |
| 210 | +); | |
| 211 | + | |
| 212 | +create table wvp_platform_gb_stream ( | |
| 213 | + id serial primary key, | |
| 214 | + platform_id character varying(50), | |
| 215 | + catalog_id character varying(50), | |
| 216 | + gb_stream_id integer, | |
| 217 | + constraint uk_platform_gb_stream_platform_id_catalog_id_gb_stream_id unique (platform_id, catalog_id, gb_stream_id) | |
| 218 | +); | |
| 219 | + | |
| 220 | +create table wvp_stream_proxy ( | |
| 221 | + id serial primary key, | |
| 222 | + type character varying(50), | |
| 223 | + app character varying(255), | |
| 224 | + stream character varying(255), | |
| 225 | + url character varying(255), | |
| 226 | + src_url character varying(255), | |
| 227 | + dst_url character varying(255), | |
| 228 | + timeout_ms integer, | |
| 229 | + ffmpeg_cmd_key character varying(255), | |
| 230 | + rtp_type character varying(50), | |
| 231 | + media_server_id character varying(50), | |
| 232 | + enable_audio bool default false, | |
| 233 | + enable_mp4 bool default false, | |
| 234 | + enable bool default false, | |
| 235 | + status boolean, | |
| 236 | + enable_remove_none_reader bool default false, | |
| 237 | + create_time character varying(50), | |
| 238 | + name character varying(255), | |
| 239 | + update_time character varying(50), | |
| 240 | + enable_disable_none_reader bool default false, | |
| 241 | + constraint uk_stream_proxy_app_stream unique (app, stream) | |
| 242 | +); | |
| 243 | + | |
| 244 | +create table wvp_stream_push ( | |
| 245 | + id serial primary key, | |
| 246 | + app character varying(255), | |
| 247 | + stream character varying(255), | |
| 248 | + total_reader_count character varying(50), | |
| 249 | + origin_type integer, | |
| 250 | + origin_type_str character varying(50), | |
| 251 | + create_time character varying(50), | |
| 252 | + alive_second integer, | |
| 253 | + media_server_id character varying(50), | |
| 254 | + push_time character varying(50), | |
| 255 | + status bool default false, | |
| 256 | + update_time character varying(50), | |
| 257 | + push_ing bool default false, | |
| 258 | + self bool default false, | |
| 259 | + constraint uk_stream_push_app_stream unique (app, stream) | |
| 260 | +); | |
| 261 | + | |
| 262 | +create table wvp_user ( | |
| 263 | + id serial primary key, | |
| 264 | + username character varying(255), | |
| 265 | + password character varying(255), | |
| 266 | + role_id integer, | |
| 267 | + create_time character varying(50), | |
| 268 | + update_time character varying(50), | |
| 269 | + push_key character varying(50), | |
| 270 | + constraint uk_user_username unique (username) | |
| 271 | +); | |
| 272 | + | |
| 273 | +create table wvp_user_role ( | |
| 274 | + id serial primary key, | |
| 275 | + name character varying(50), | |
| 276 | + authority character varying(50), | |
| 277 | + create_time character varying(50), | |
| 278 | + update_time character varying(50) | |
| 279 | +); | |
| 280 | + | |
| 281 | +/*初始数据*/ | |
| 282 | +INSERT INTO wvp_user VALUES (1, 'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3'); | |
| 283 | +INSERT INTO wvp_user_role VALUES (1, 'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57'); | |
| 6 | 284 | |
| 7 | -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; | |
| 8 | -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; | |
| 9 | -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; | |
| 10 | -/*!50503 SET NAMES utf8mb4 */; | |
| 11 | -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; | |
| 12 | -/*!40103 SET TIME_ZONE='+00:00' */; | |
| 13 | -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; | |
| 14 | -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; | |
| 15 | -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; | |
| 16 | -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; | |
| 17 | 285 | |
| 18 | --- | |
| 19 | --- Table structure for table `device` | |
| 20 | --- | |
| 21 | 286 | |
| 22 | -DROP TABLE IF EXISTS `device`; | |
| 23 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 24 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 25 | -CREATE TABLE `device` ( | |
| 26 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 27 | - `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 28 | - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 29 | - `manufacturer` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 30 | - `model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 31 | - `firmware` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 32 | - `transport` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 33 | - `streamMode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 34 | - `online` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 35 | - `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 36 | - `registerTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 37 | - `keepaliveTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 38 | - `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 39 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 40 | - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 41 | - `port` int DEFAULT NULL, | |
| 42 | - `expires` int DEFAULT NULL, | |
| 43 | - `keepaliveIntervalTime` int DEFAULT NULL, | |
| 44 | - `subscribeCycleForCatalog` int DEFAULT NULL, | |
| 45 | - `hostAddress` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 46 | - `charset` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 47 | - `subscribeCycleForMobilePosition` int DEFAULT NULL, | |
| 48 | - `mobilePositionSubmissionInterval` int DEFAULT '5', | |
| 49 | - `subscribeCycleForAlarm` int DEFAULT NULL, | |
| 50 | - `ssrcCheck` int DEFAULT '0', | |
| 51 | - `asMessageChannel` int DEFAULT '0', | |
| 52 | - `geoCoordSys` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 53 | - `treeType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 54 | - `custom_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 55 | - `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 56 | - `sdpIp` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 57 | - `localIp` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 58 | - PRIMARY KEY (`id`), | |
| 59 | - UNIQUE KEY `device_deviceId_uindex` (`deviceId`) | |
| 60 | -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; | |
| 61 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 62 | - | |
| 63 | --- | |
| 64 | --- Dumping data for table `device` | |
| 65 | --- | |
| 66 | - | |
| 67 | -LOCK TABLES `device` WRITE; | |
| 68 | -/*!40000 ALTER TABLE `device` DISABLE KEYS */; | |
| 69 | -/*!40000 ALTER TABLE `device` ENABLE KEYS */; | |
| 70 | -UNLOCK TABLES; | |
| 71 | - | |
| 72 | --- | |
| 73 | --- Table structure for table `device_alarm` | |
| 74 | --- | |
| 75 | - | |
| 76 | -DROP TABLE IF EXISTS `device_alarm`; | |
| 77 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 78 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 79 | -CREATE TABLE `device_alarm` ( | |
| 80 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 81 | - `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 82 | - `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 83 | - `alarmPriority` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 84 | - `alarmMethod` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 85 | - `alarmTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 86 | - `alarmDescription` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 87 | - `longitude` double DEFAULT NULL, | |
| 88 | - `latitude` double DEFAULT NULL, | |
| 89 | - `alarmType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 90 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 91 | - PRIMARY KEY (`id`) USING BTREE | |
| 92 | -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 93 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 94 | - | |
| 95 | --- | |
| 96 | --- Dumping data for table `device_alarm` | |
| 97 | --- | |
| 98 | - | |
| 99 | -LOCK TABLES `device_alarm` WRITE; | |
| 100 | -/*!40000 ALTER TABLE `device_alarm` DISABLE KEYS */; | |
| 101 | -/*!40000 ALTER TABLE `device_alarm` ENABLE KEYS */; | |
| 102 | -UNLOCK TABLES; | |
| 103 | - | |
| 104 | --- | |
| 105 | --- Table structure for table `device_channel` | |
| 106 | --- | |
| 107 | - | |
| 108 | -DROP TABLE IF EXISTS `device_channel`; | |
| 109 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 110 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 111 | -CREATE TABLE `device_channel` ( | |
| 112 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 113 | - `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 114 | - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 115 | - `manufacture` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 116 | - `model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 117 | - `owner` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 118 | - `civilCode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 119 | - `block` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 120 | - `address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 121 | - `parentId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 122 | - `safetyWay` int DEFAULT NULL, | |
| 123 | - `registerWay` int DEFAULT NULL, | |
| 124 | - `certNum` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 125 | - `certifiable` int DEFAULT NULL, | |
| 126 | - `errCode` int DEFAULT NULL, | |
| 127 | - `endTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 128 | - `secrecy` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 129 | - `ipAddress` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 130 | - `port` int DEFAULT NULL, | |
| 131 | - `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 132 | - `PTZType` int DEFAULT NULL, | |
| 133 | - `status` int DEFAULT NULL, | |
| 134 | - `longitude` double DEFAULT NULL, | |
| 135 | - `latitude` double DEFAULT NULL, | |
| 136 | - `streamId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 137 | - `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 138 | - `parental` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 139 | - `hasAudio` bit(1) DEFAULT NULL, | |
| 140 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 141 | - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 142 | - `subCount` int DEFAULT '0', | |
| 143 | - `longitudeGcj02` double DEFAULT NULL, | |
| 144 | - `latitudeGcj02` double DEFAULT NULL, | |
| 145 | - `longitudeWgs84` double DEFAULT NULL, | |
| 146 | - `latitudeWgs84` double DEFAULT NULL, | |
| 147 | - `businessGroupId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 148 | - `gpsTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 149 | - PRIMARY KEY (`id`), | |
| 150 | - UNIQUE KEY `device_channel_id_uindex` (`id`), | |
| 151 | - UNIQUE KEY `device_channel_pk` (`channelId`,`deviceId`) | |
| 152 | -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; | |
| 153 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 154 | - | |
| 155 | --- | |
| 156 | --- Dumping data for table `device_channel` | |
| 157 | --- | |
| 158 | - | |
| 159 | -LOCK TABLES `device_channel` WRITE; | |
| 160 | -/*!40000 ALTER TABLE `device_channel` DISABLE KEYS */; | |
| 161 | -/*!40000 ALTER TABLE `device_channel` ENABLE KEYS */; | |
| 162 | -UNLOCK TABLES; | |
| 163 | - | |
| 164 | --- | |
| 165 | --- Table structure for table `device_mobile_position` | |
| 166 | --- | |
| 167 | - | |
| 168 | -DROP TABLE IF EXISTS `device_mobile_position`; | |
| 169 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 170 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 171 | -CREATE TABLE `device_mobile_position` ( | |
| 172 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 173 | - `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 174 | - `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 175 | - `deviceName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 176 | - `time` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 177 | - `longitude` double NOT NULL, | |
| 178 | - `latitude` double NOT NULL, | |
| 179 | - `altitude` double DEFAULT NULL, | |
| 180 | - `speed` double DEFAULT NULL, | |
| 181 | - `direction` double DEFAULT NULL, | |
| 182 | - `reportSource` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 183 | - `longitudeGcj02` double DEFAULT NULL, | |
| 184 | - `latitudeGcj02` double DEFAULT NULL, | |
| 185 | - `longitudeWgs84` double DEFAULT NULL, | |
| 186 | - `latitudeWgs84` double DEFAULT NULL, | |
| 187 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 188 | - PRIMARY KEY (`id`) | |
| 189 | -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; | |
| 190 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 191 | - | |
| 192 | --- | |
| 193 | --- Dumping data for table `device_mobile_position` | |
| 194 | --- | |
| 195 | - | |
| 196 | -LOCK TABLES `device_mobile_position` WRITE; | |
| 197 | -/*!40000 ALTER TABLE `device_mobile_position` DISABLE KEYS */; | |
| 198 | -/*!40000 ALTER TABLE `device_mobile_position` ENABLE KEYS */; | |
| 199 | -UNLOCK TABLES; | |
| 200 | - | |
| 201 | --- | |
| 202 | --- Table structure for table `gb_stream` | |
| 203 | --- | |
| 204 | - | |
| 205 | -DROP TABLE IF EXISTS `gb_stream`; | |
| 206 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 207 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 208 | -CREATE TABLE `gb_stream` ( | |
| 209 | - `gbStreamId` int NOT NULL AUTO_INCREMENT, | |
| 210 | - `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 211 | - `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 212 | - `gbId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 213 | - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 214 | - `longitude` double DEFAULT NULL, | |
| 215 | - `latitude` double DEFAULT NULL, | |
| 216 | - `streamType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 217 | - `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 218 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 219 | - PRIMARY KEY (`gbStreamId`) USING BTREE, | |
| 220 | - UNIQUE KEY `app` (`app`,`stream`) USING BTREE, | |
| 221 | - UNIQUE KEY `gbId` (`gbId`) USING BTREE | |
| 222 | -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 223 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 224 | - | |
| 225 | --- | |
| 226 | --- Dumping data for table `gb_stream` | |
| 227 | --- | |
| 228 | - | |
| 229 | -LOCK TABLES `gb_stream` WRITE; | |
| 230 | -/*!40000 ALTER TABLE `gb_stream` DISABLE KEYS */; | |
| 231 | -/*!40000 ALTER TABLE `gb_stream` ENABLE KEYS */; | |
| 232 | -UNLOCK TABLES; | |
| 233 | - | |
| 234 | --- | |
| 235 | --- Table structure for table `log` | |
| 236 | --- | |
| 237 | - | |
| 238 | -DROP TABLE IF EXISTS `log`; | |
| 239 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 240 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 241 | -CREATE TABLE `log` ( | |
| 242 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 243 | - `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 244 | - `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 245 | - `uri` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 246 | - `address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 247 | - `result` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 248 | - `timing` bigint NOT NULL, | |
| 249 | - `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 250 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 251 | - PRIMARY KEY (`id`) USING BTREE | |
| 252 | -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 253 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 254 | - | |
| 255 | --- | |
| 256 | --- Dumping data for table `log` | |
| 257 | --- | |
| 258 | - | |
| 259 | -LOCK TABLES `log` WRITE; | |
| 260 | -/*!40000 ALTER TABLE `log` DISABLE KEYS */; | |
| 261 | -/*!40000 ALTER TABLE `log` ENABLE KEYS */; | |
| 262 | -UNLOCK TABLES; | |
| 263 | - | |
| 264 | --- | |
| 265 | --- Table structure for table `media_server` | |
| 266 | --- | |
| 267 | - | |
| 268 | -DROP TABLE IF EXISTS `media_server`; | |
| 269 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 270 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 271 | -CREATE TABLE `media_server` ( | |
| 272 | - `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 273 | - `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 274 | - `hookIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 275 | - `sdpIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 276 | - `streamIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 277 | - `httpPort` int NOT NULL, | |
| 278 | - `httpSSlPort` int NOT NULL, | |
| 279 | - `rtmpPort` int NOT NULL, | |
| 280 | - `rtmpSSlPort` int NOT NULL, | |
| 281 | - `rtpProxyPort` int NOT NULL, | |
| 282 | - `rtspPort` int NOT NULL, | |
| 283 | - `rtspSSLPort` int NOT NULL, | |
| 284 | - `autoConfig` int NOT NULL, | |
| 285 | - `secret` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 286 | - `rtpEnable` int NOT NULL, | |
| 287 | - `rtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 288 | - `recordAssistPort` int NOT NULL, | |
| 289 | - `defaultServer` int NOT NULL, | |
| 290 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 291 | - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 292 | - `hookAliveInterval` int NOT NULL, | |
| 293 | - PRIMARY KEY (`id`) USING BTREE, | |
| 294 | - UNIQUE KEY `media_server_i` (`ip`,`httpPort`) USING BTREE | |
| 295 | -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 296 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 297 | - | |
| 298 | --- | |
| 299 | --- Dumping data for table `media_server` | |
| 300 | --- | |
| 301 | - | |
| 302 | -LOCK TABLES `media_server` WRITE; | |
| 303 | -/*!40000 ALTER TABLE `media_server` DISABLE KEYS */; | |
| 304 | -/*!40000 ALTER TABLE `media_server` ENABLE KEYS */; | |
| 305 | -UNLOCK TABLES; | |
| 306 | - | |
| 307 | --- | |
| 308 | --- Table structure for table `parent_platform` | |
| 309 | --- | |
| 310 | - | |
| 311 | -DROP TABLE IF EXISTS `parent_platform`; | |
| 312 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 313 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 314 | -CREATE TABLE `parent_platform` ( | |
| 315 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 316 | - `enable` int DEFAULT NULL, | |
| 317 | - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 318 | - `serverGBId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 319 | - `serverGBDomain` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 320 | - `serverIP` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 321 | - `serverPort` int DEFAULT NULL, | |
| 322 | - `deviceGBId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 323 | - `deviceIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 324 | - `devicePort` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 325 | - `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 326 | - `password` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 327 | - `expires` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 328 | - `keepTimeout` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 329 | - `transport` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 330 | - `characterSet` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 331 | - `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 332 | - `ptz` int DEFAULT NULL, | |
| 333 | - `rtcp` int DEFAULT NULL, | |
| 334 | - `asMessageChannel` int DEFAULT '0', | |
| 335 | - `status` bit(1) DEFAULT NULL, | |
| 336 | - `startOfflinePush` int DEFAULT '0', | |
| 337 | - `administrativeDivision` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 338 | - `catalogGroup` int DEFAULT '1', | |
| 339 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 340 | - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 341 | - `treeType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 342 | - PRIMARY KEY (`id`), | |
| 343 | - UNIQUE KEY `parent_platform_id_uindex` (`id`), | |
| 344 | - UNIQUE KEY `parent_platform_pk` (`serverGBId`) | |
| 345 | -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 346 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 347 | - | |
| 348 | --- | |
| 349 | --- Dumping data for table `parent_platform` | |
| 350 | --- | |
| 351 | - | |
| 352 | -LOCK TABLES `parent_platform` WRITE; | |
| 353 | -/*!40000 ALTER TABLE `parent_platform` DISABLE KEYS */; | |
| 354 | -/*!40000 ALTER TABLE `parent_platform` ENABLE KEYS */; | |
| 355 | -UNLOCK TABLES; | |
| 356 | - | |
| 357 | --- | |
| 358 | --- Table structure for table `platform_catalog` | |
| 359 | --- | |
| 360 | - | |
| 361 | -DROP TABLE IF EXISTS `platform_catalog`; | |
| 362 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 363 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 364 | -CREATE TABLE `platform_catalog` ( | |
| 365 | - `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 366 | - `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 367 | - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 368 | - `parentId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 369 | - `civilCode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 370 | - `businessGroupId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 371 | - PRIMARY KEY (`id`) USING BTREE | |
| 372 | -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 373 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 374 | - | |
| 375 | --- | |
| 376 | --- Dumping data for table `platform_catalog` | |
| 377 | --- | |
| 378 | - | |
| 379 | -LOCK TABLES `platform_catalog` WRITE; | |
| 380 | -/*!40000 ALTER TABLE `platform_catalog` DISABLE KEYS */; | |
| 381 | -/*!40000 ALTER TABLE `platform_catalog` ENABLE KEYS */; | |
| 382 | -UNLOCK TABLES; | |
| 383 | - | |
| 384 | --- | |
| 385 | --- Table structure for table `platform_gb_channel` | |
| 386 | --- | |
| 387 | - | |
| 388 | -DROP TABLE IF EXISTS `platform_gb_channel`; | |
| 389 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 390 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 391 | -CREATE TABLE `platform_gb_channel` ( | |
| 392 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 393 | - `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 394 | - `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 395 | - `deviceChannelId` int NOT NULL, | |
| 396 | - PRIMARY KEY (`id`) | |
| 397 | -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; | |
| 398 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 399 | - | |
| 400 | --- | |
| 401 | --- Dumping data for table `platform_gb_channel` | |
| 402 | --- | |
| 403 | - | |
| 404 | -LOCK TABLES `platform_gb_channel` WRITE; | |
| 405 | -/*!40000 ALTER TABLE `platform_gb_channel` DISABLE KEYS */; | |
| 406 | -/*!40000 ALTER TABLE `platform_gb_channel` ENABLE KEYS */; | |
| 407 | -UNLOCK TABLES; | |
| 408 | - | |
| 409 | --- | |
| 410 | --- Table structure for table `platform_gb_stream` | |
| 411 | --- | |
| 412 | - | |
| 413 | -DROP TABLE IF EXISTS `platform_gb_stream`; | |
| 414 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 415 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 416 | -CREATE TABLE `platform_gb_stream` ( | |
| 417 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 418 | - `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 419 | - `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 420 | - `gbStreamId` int NOT NULL, | |
| 421 | - PRIMARY KEY (`id`), | |
| 422 | - UNIQUE KEY `platform_gb_stream_pk` (`platformId`,`catalogId`,`gbStreamId`) | |
| 423 | -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 424 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 425 | - | |
| 426 | --- | |
| 427 | --- Dumping data for table `platform_gb_stream` | |
| 428 | --- | |
| 429 | - | |
| 430 | -LOCK TABLES `platform_gb_stream` WRITE; | |
| 431 | -/*!40000 ALTER TABLE `platform_gb_stream` DISABLE KEYS */; | |
| 432 | -/*!40000 ALTER TABLE `platform_gb_stream` ENABLE KEYS */; | |
| 433 | -UNLOCK TABLES; | |
| 434 | - | |
| 435 | --- | |
| 436 | --- Table structure for table `stream_proxy` | |
| 437 | --- | |
| 438 | - | |
| 439 | -DROP TABLE IF EXISTS `stream_proxy`; | |
| 440 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 441 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 442 | -CREATE TABLE `stream_proxy` ( | |
| 443 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 444 | - `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 445 | - `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 446 | - `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 447 | - `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 448 | - `src_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 449 | - `dst_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 450 | - `timeout_ms` int DEFAULT NULL, | |
| 451 | - `ffmpeg_cmd_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 452 | - `rtp_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 453 | - `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 454 | - `enable_audio` bit(1) DEFAULT NULL, | |
| 455 | - `enable_mp4` bit(1) DEFAULT NULL, | |
| 456 | - `enable` bit(1) NOT NULL, | |
| 457 | - `status` bit(1) NOT NULL, | |
| 458 | - `enable_remove_none_reader` bit(1) NOT NULL, | |
| 459 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 460 | - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 461 | - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 462 | - `enable_disable_none_reader` bit(1) DEFAULT NULL, | |
| 463 | - PRIMARY KEY (`id`), | |
| 464 | - UNIQUE KEY `stream_proxy_pk` (`app`,`stream`) | |
| 465 | -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; | |
| 466 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 467 | - | |
| 468 | --- | |
| 469 | --- Dumping data for table `stream_proxy` | |
| 470 | --- | |
| 471 | - | |
| 472 | -LOCK TABLES `stream_proxy` WRITE; | |
| 473 | -/*!40000 ALTER TABLE `stream_proxy` DISABLE KEYS */; | |
| 474 | -/*!40000 ALTER TABLE `stream_proxy` ENABLE KEYS */; | |
| 475 | -UNLOCK TABLES; | |
| 476 | - | |
| 477 | --- | |
| 478 | --- Table structure for table `stream_push` | |
| 479 | --- | |
| 480 | - | |
| 481 | -DROP TABLE IF EXISTS `stream_push`; | |
| 482 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 483 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 484 | -CREATE TABLE `stream_push` ( | |
| 485 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 486 | - `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 487 | - `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 488 | - `totalReaderCount` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 489 | - `originType` int DEFAULT NULL, | |
| 490 | - `originTypeStr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 491 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 492 | - `aliveSecond` int DEFAULT NULL, | |
| 493 | - `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 494 | - `serverId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 495 | - `pushTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 496 | - `status` int DEFAULT NULL, | |
| 497 | - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 498 | - `pushIng` int DEFAULT NULL, | |
| 499 | - `self` int DEFAULT NULL, | |
| 500 | - PRIMARY KEY (`id`), | |
| 501 | - UNIQUE KEY `stream_push_pk` (`app`,`stream`) | |
| 502 | -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; | |
| 503 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 504 | - | |
| 505 | --- | |
| 506 | --- Dumping data for table `stream_push` | |
| 507 | --- | |
| 508 | - | |
| 509 | -LOCK TABLES `stream_push` WRITE; | |
| 510 | -/*!40000 ALTER TABLE `stream_push` DISABLE KEYS */; | |
| 511 | -/*!40000 ALTER TABLE `stream_push` ENABLE KEYS */; | |
| 512 | -UNLOCK TABLES; | |
| 513 | - | |
| 514 | --- | |
| 515 | --- Table structure for table `user` | |
| 516 | --- | |
| 517 | - | |
| 518 | -DROP TABLE IF EXISTS `user`; | |
| 519 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 520 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 521 | -CREATE TABLE `user` ( | |
| 522 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 523 | - `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 524 | - `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 525 | - `roleId` int NOT NULL, | |
| 526 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 527 | - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 528 | - `pushKey` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, | |
| 529 | - PRIMARY KEY (`id`) USING BTREE, | |
| 530 | - UNIQUE KEY `user_username_uindex` (`username`) USING BTREE | |
| 531 | -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 532 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 533 | - | |
| 534 | --- | |
| 535 | --- Dumping data for table `user` | |
| 536 | --- | |
| 537 | - | |
| 538 | -LOCK TABLES `user` WRITE; | |
| 539 | -/*!40000 ALTER TABLE `user` DISABLE KEYS */; | |
| 540 | -INSERT INTO `user` VALUES (1,'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3'); | |
| 541 | -/*!40000 ALTER TABLE `user` ENABLE KEYS */; | |
| 542 | -UNLOCK TABLES; | |
| 543 | - | |
| 544 | --- | |
| 545 | --- Table structure for table `user_role` | |
| 546 | --- | |
| 547 | - | |
| 548 | -DROP TABLE IF EXISTS `user_role`; | |
| 549 | -/*!40101 SET @saved_cs_client = @@character_set_client */; | |
| 550 | -/*!50503 SET character_set_client = utf8mb4 */; | |
| 551 | -CREATE TABLE `user_role` ( | |
| 552 | - `id` int NOT NULL AUTO_INCREMENT, | |
| 553 | - `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 554 | - `authority` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 555 | - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 556 | - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, | |
| 557 | - PRIMARY KEY (`id`) USING BTREE | |
| 558 | -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC; | |
| 559 | -/*!40101 SET character_set_client = @saved_cs_client */; | |
| 560 | - | |
| 561 | --- | |
| 562 | --- Dumping data for table `user_role` | |
| 563 | --- | |
| 564 | - | |
| 565 | -LOCK TABLES `user_role` WRITE; | |
| 566 | -/*!40000 ALTER TABLE `user_role` DISABLE KEYS */; | |
| 567 | -INSERT INTO `user_role` VALUES (1,'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57'); | |
| 568 | -/*!40000 ALTER TABLE `user_role` ENABLE KEYS */; | |
| 569 | -UNLOCK TABLES; | |
| 570 | -/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; | |
| 571 | - | |
| 572 | -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; | |
| 573 | -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; | |
| 574 | -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; | |
| 575 | -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; | |
| 576 | -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; | |
| 577 | -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; | |
| 578 | -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; | |
| 579 | - | |
| 580 | --- Dump completed on 2022-11-29 11:47:46 | |
| 581 | 287 | \ No newline at end of file | ... | ... |
src/main/java/com/genersoft/iot/vmp/common/CivilCodePo.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.common; | |
| 2 | + | |
| 3 | +public class CivilCodePo { | |
| 4 | + | |
| 5 | + private String code; | |
| 6 | + | |
| 7 | + private String name; | |
| 8 | + | |
| 9 | + private String parentCode; | |
| 10 | + | |
| 11 | + public static CivilCodePo getInstance(String[] infoArray) { | |
| 12 | + CivilCodePo civilCodePo = new CivilCodePo(); | |
| 13 | + civilCodePo.setCode(infoArray[0]); | |
| 14 | + civilCodePo.setName(infoArray[1]); | |
| 15 | + civilCodePo.setParentCode(infoArray[2]); | |
| 16 | + return civilCodePo; | |
| 17 | + } | |
| 18 | + | |
| 19 | + public String getCode() { | |
| 20 | + return code; | |
| 21 | + } | |
| 22 | + | |
| 23 | + public void setCode(String code) { | |
| 24 | + this.code = code; | |
| 25 | + } | |
| 26 | + | |
| 27 | + public String getName() { | |
| 28 | + return name; | |
| 29 | + } | |
| 30 | + | |
| 31 | + public void setName(String name) { | |
| 32 | + this.name = name; | |
| 33 | + } | |
| 34 | + | |
| 35 | + public String getParentCode() { | |
| 36 | + return parentCode; | |
| 37 | + } | |
| 38 | + | |
| 39 | + public void setParentCode(String parentCode) { | |
| 40 | + this.parentCode = parentCode; | |
| 41 | + } | |
| 42 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/common/GeneralCallback.java
0 → 100644
src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java
| 1 | 1 | package com.genersoft.iot.vmp.common; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | 5 | |
| 5 | 6 | /** |
| 6 | 7 | * 记录每次发送invite消息的状态 |
| ... | ... | @@ -28,7 +29,7 @@ public class InviteInfo { |
| 28 | 29 | private StreamInfo streamInfo; |
| 29 | 30 | |
| 30 | 31 | |
| 31 | - public static InviteInfo getinviteInfo(String deviceId, String channelId, String stream, SSRCInfo ssrcInfo, | |
| 32 | + public static InviteInfo getInviteInfo(String deviceId, String channelId, String stream, SSRCInfo ssrcInfo, | |
| 32 | 33 | String receiveIp, Integer receivePort, String streamMode, |
| 33 | 34 | InviteSessionType type, InviteSessionStatus status) { |
| 34 | 35 | InviteInfo inviteInfo = new InviteInfo(); |
| ... | ... | @@ -123,4 +124,21 @@ public class InviteInfo { |
| 123 | 124 | public void setStreamMode(String streamMode) { |
| 124 | 125 | this.streamMode = streamMode; |
| 125 | 126 | } |
| 127 | + | |
| 128 | + | |
| 129 | + /*=========================设备主子码流逻辑START====================*/ | |
| 130 | + @Schema(description = "是否为子码流(true-是,false-主码流)") | |
| 131 | + private boolean subStream; | |
| 132 | + | |
| 133 | + public boolean isSubStream() { | |
| 134 | + return subStream; | |
| 135 | + } | |
| 136 | + | |
| 137 | + public void setSubStream(boolean subStream) { | |
| 138 | + this.subStream = subStream; | |
| 139 | + } | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 126 | 144 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
| ... | ... | @@ -528,4 +528,19 @@ public class StreamInfo implements Serializable, Cloneable{ |
| 528 | 528 | } |
| 529 | 529 | return instance; |
| 530 | 530 | } |
| 531 | + | |
| 532 | + | |
| 533 | + /*=========================设备主子码流逻辑START====================*/ | |
| 534 | + @Schema(description = "是否为子码流(true-是,false-主码流)") | |
| 535 | + private boolean subStream; | |
| 536 | + | |
| 537 | + public boolean isSubStream() { | |
| 538 | + return subStream; | |
| 539 | + } | |
| 540 | + | |
| 541 | + public void setSubStream(boolean subStream) { | |
| 542 | + this.subStream = subStream; | |
| 543 | + } | |
| 544 | + | |
| 545 | + | |
| 531 | 546 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
| ... | ... | @@ -108,6 +108,11 @@ public class VideoManagerConstants { |
| 108 | 108 | public static final String VM_MSG_STREAM_PUSH_RESPONSE = "VM_MSG_STREAM_PUSH_RESPONSE"; |
| 109 | 109 | |
| 110 | 110 | /** |
| 111 | + * redis 通知平台关闭推流 | |
| 112 | + */ | |
| 113 | + public static final String VM_MSG_STREAM_PUSH_CLOSE = "VM_MSG_STREAM_PUSH_CLOSE"; | |
| 114 | + | |
| 115 | + /** | |
| 111 | 116 | * redis 消息请求所有的在线通道 |
| 112 | 117 | */ |
| 113 | 118 | public static final String VM_MSG_GET_ALL_ONLINE_REQUESTED = "VM_MSG_GET_ALL_ONLINE_REQUESTED"; | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/CivilCodeFileConf.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.conf; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.common.CivilCodePo; | |
| 4 | +import org.ehcache.impl.internal.concurrent.ConcurrentHashMap; | |
| 5 | +import org.slf4j.Logger; | |
| 6 | +import org.slf4j.LoggerFactory; | |
| 7 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 8 | +import org.springframework.boot.CommandLineRunner; | |
| 9 | +import org.springframework.context.annotation.Configuration; | |
| 10 | +import org.springframework.context.annotation.Lazy; | |
| 11 | +import org.springframework.core.annotation.Order; | |
| 12 | +import org.springframework.core.io.ClassPathResource; | |
| 13 | +import org.springframework.util.ObjectUtils; | |
| 14 | + | |
| 15 | +import java.io.*; | |
| 16 | +import java.nio.file.Files; | |
| 17 | +import java.util.Map; | |
| 18 | + | |
| 19 | +/** | |
| 20 | + * 启动时读取行政区划表 | |
| 21 | + */ | |
| 22 | +@Configuration | |
| 23 | +@Order(value=14) | |
| 24 | +public class CivilCodeFileConf implements CommandLineRunner { | |
| 25 | + | |
| 26 | + private final static Logger logger = LoggerFactory.getLogger(CivilCodeFileConf.class); | |
| 27 | + | |
| 28 | + private final Map<String, CivilCodePo> civilCodeMap= new ConcurrentHashMap<>(); | |
| 29 | + | |
| 30 | + @Autowired | |
| 31 | + @Lazy | |
| 32 | + private UserSetting userSetting; | |
| 33 | + | |
| 34 | + @Override | |
| 35 | + public void run(String... args) throws Exception { | |
| 36 | + if (ObjectUtils.isEmpty(userSetting.getCivilCodeFile())) { | |
| 37 | + logger.warn("[行政区划] 文件未设置,可能造成目录刷新结果不完整"); | |
| 38 | + return; | |
| 39 | + } | |
| 40 | + InputStream inputStream; | |
| 41 | + if (userSetting.getCivilCodeFile().startsWith("classpath:")){ | |
| 42 | + String filePath = userSetting.getCivilCodeFile().substring("classpath:".length()); | |
| 43 | + ClassPathResource civilCodeFile = new ClassPathResource(filePath); | |
| 44 | + if (!civilCodeFile.exists()) { | |
| 45 | + logger.warn("[行政区划] 文件<{}>不存在,可能造成目录刷新结果不完整", userSetting.getCivilCodeFile()); | |
| 46 | + return; | |
| 47 | + } | |
| 48 | + inputStream = civilCodeFile.getInputStream(); | |
| 49 | + | |
| 50 | + }else { | |
| 51 | + File civilCodeFile = new File(userSetting.getCivilCodeFile()); | |
| 52 | + if (!civilCodeFile.exists()) { | |
| 53 | + logger.warn("[行政区划] 文件<{}>不存在,可能造成目录刷新结果不完整", userSetting.getCivilCodeFile()); | |
| 54 | + return; | |
| 55 | + } | |
| 56 | + inputStream = Files.newInputStream(civilCodeFile.toPath()); | |
| 57 | + } | |
| 58 | + | |
| 59 | + BufferedReader inputStreamReader = new BufferedReader(new InputStreamReader(inputStream)); | |
| 60 | + int index = -1; | |
| 61 | + String line; | |
| 62 | + while ((line = inputStreamReader.readLine()) != null) { | |
| 63 | + index ++; | |
| 64 | + if (index == 0) { | |
| 65 | + continue; | |
| 66 | + } | |
| 67 | + String[] infoArray = line.split(","); | |
| 68 | + CivilCodePo civilCodePo = CivilCodePo.getInstance(infoArray); | |
| 69 | + civilCodeMap.put(civilCodePo.getCode(), civilCodePo); | |
| 70 | + } | |
| 71 | + inputStreamReader.close(); | |
| 72 | + inputStream.close(); | |
| 73 | + if (civilCodeMap.size() == 0) { | |
| 74 | + logger.warn("[行政区划] 文件内容为空,可能造成目录刷新结果不完整"); | |
| 75 | + }else { | |
| 76 | + logger.info("[行政区划] 加载成功,共加载数据{}条", civilCodeMap.size()); | |
| 77 | + } | |
| 78 | + } | |
| 79 | + | |
| 80 | + public CivilCodePo getParentCode(String code) { | |
| 81 | + if (code.length() > 8) { | |
| 82 | + return null; | |
| 83 | + } | |
| 84 | + if (code.length() == 8) { | |
| 85 | + String parentCode = code.substring(0, 6); | |
| 86 | + return civilCodeMap.get(parentCode); | |
| 87 | + }else { | |
| 88 | + CivilCodePo civilCodePo = civilCodeMap.get(code); | |
| 89 | + if (civilCodePo == null){ | |
| 90 | + return null; | |
| 91 | + } | |
| 92 | + String parentCode = civilCodePo.getParentCode(); | |
| 93 | + if (parentCode == null) { | |
| 94 | + return null; | |
| 95 | + } | |
| 96 | + return civilCodeMap.get(parentCode); | |
| 97 | + } | |
| 98 | + | |
| 99 | + } | |
| 100 | + | |
| 101 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
| ... | ... | @@ -2,11 +2,11 @@ package com.genersoft.iot.vmp.conf; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 4 | 4 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 5 | -import org.junit.jupiter.api.Order; | |
| 6 | 5 | import org.slf4j.Logger; |
| 7 | 6 | import org.slf4j.LoggerFactory; |
| 8 | 7 | import org.springframework.beans.factory.annotation.Value; |
| 9 | 8 | import org.springframework.context.annotation.Configuration; |
| 9 | +import org.springframework.core.annotation.Order; | |
| 10 | 10 | import org.springframework.util.ObjectUtils; |
| 11 | 11 | |
| 12 | 12 | import java.net.InetAddress; | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/MybatisConfig.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.conf; | |
| 2 | + | |
| 3 | +import org.apache.ibatis.logging.stdout.StdOutImpl; | |
| 4 | +import org.apache.ibatis.session.SqlSessionFactory; | |
| 5 | +import org.mybatis.spring.SqlSessionFactoryBean; | |
| 6 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 7 | +import org.springframework.context.annotation.Bean; | |
| 8 | +import org.springframework.context.annotation.Configuration; | |
| 9 | +import org.springframework.core.annotation.Order; | |
| 10 | + | |
| 11 | +import javax.sql.DataSource; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * 配置mybatis | |
| 15 | + */ | |
| 16 | +@Configuration | |
| 17 | +@Order(value=1) | |
| 18 | +public class MybatisConfig { | |
| 19 | + | |
| 20 | + @Autowired | |
| 21 | + private UserSetting userSetting; | |
| 22 | + | |
| 23 | + @Bean | |
| 24 | + public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { | |
| 25 | + final SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean(); | |
| 26 | + sqlSessionFactory.setDataSource(dataSource); | |
| 27 | + org.apache.ibatis.session.Configuration config = new org.apache.ibatis.session.Configuration(); | |
| 28 | + if (userSetting.getSqlLog()){ | |
| 29 | + config.setLogImpl(StdOutImpl.class); | |
| 30 | + } | |
| 31 | + config.setMapUnderscoreToCamelCase(true); | |
| 32 | + sqlSessionFactory.setConfiguration(config); | |
| 33 | + return sqlSessionFactory.getObject(); | |
| 34 | + } | |
| 35 | + | |
| 36 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
| ... | ... | @@ -5,7 +5,7 @@ import com.genersoft.iot.vmp.service.IMediaServerService; |
| 5 | 5 | import org.apache.http.HttpHost; |
| 6 | 6 | import org.apache.http.HttpRequest; |
| 7 | 7 | import org.apache.http.HttpResponse; |
| 8 | -import org.junit.jupiter.api.Order; | |
| 8 | +import org.springframework.core.annotation.Order; | |
| 9 | 9 | import org.mitre.dsmiley.httpproxy.ProxyServlet; |
| 10 | 10 | import org.slf4j.Logger; |
| 11 | 11 | import org.slf4j.LoggerFactory; | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java
| ... | ... | @@ -4,7 +4,7 @@ import io.swagger.v3.oas.models.OpenAPI; |
| 4 | 4 | import io.swagger.v3.oas.models.info.Contact; |
| 5 | 5 | import io.swagger.v3.oas.models.info.Info; |
| 6 | 6 | import io.swagger.v3.oas.models.info.License; |
| 7 | -import org.junit.jupiter.api.Order; | |
| 7 | +import org.springframework.core.annotation.Order; | |
| 8 | 8 | import org.springdoc.core.GroupedOpenApi; |
| 9 | 9 | import org.springframework.beans.factory.annotation.Value; |
| 10 | 10 | import org.springframework.context.annotation.Bean; | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/ThreadPoolTaskConfig.java
| 1 | 1 | package com.genersoft.iot.vmp.conf; |
| 2 | 2 | |
| 3 | -import org.junit.jupiter.api.Order; | |
| 4 | 3 | import org.springframework.context.annotation.Bean; |
| 5 | 4 | import org.springframework.context.annotation.Configuration; |
| 5 | +import org.springframework.core.annotation.Order; | |
| 6 | 6 | import org.springframework.scheduling.annotation.EnableAsync; |
| 7 | 7 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| 8 | 8 | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
| 1 | 1 | package com.genersoft.iot.vmp.conf; |
| 2 | 2 | |
| 3 | -import org.junit.jupiter.api.Order; | |
| 4 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; |
| 4 | +import org.springframework.core.annotation.Order; | |
| 5 | 5 | import org.springframework.stereotype.Component; |
| 6 | 6 | |
| 7 | 7 | import java.util.ArrayList; |
| ... | ... | @@ -50,6 +50,7 @@ public class UserSetting { |
| 50 | 50 | private Boolean pushStreamAfterAck = Boolean.FALSE; |
| 51 | 51 | |
| 52 | 52 | private Boolean sipLog = Boolean.FALSE; |
| 53 | + private Boolean sqlLog = Boolean.FALSE; | |
| 53 | 54 | private Boolean sendToPlatformsWhenIdLost = Boolean.FALSE; |
| 54 | 55 | |
| 55 | 56 | private Boolean refuseChannelStatusChannelFormNotify = Boolean.FALSE; |
| ... | ... | @@ -65,12 +66,18 @@ public class UserSetting { |
| 65 | 66 | |
| 66 | 67 | private String broadcastForPlatform = "UDP"; |
| 67 | 68 | |
| 69 | + private String civilCodeFile = "classpath:civilCode.csv"; | |
| 70 | + | |
| 68 | 71 | private List<String> interfaceAuthenticationExcludes = new ArrayList<>(); |
| 69 | 72 | |
| 70 | 73 | private List<String> allowedOrigins = new ArrayList<>(); |
| 71 | 74 | |
| 72 | 75 | private int maxNotifyCountQueue = 10000; |
| 73 | 76 | |
| 77 | + private int registerAgainAfterTime = 60; | |
| 78 | + | |
| 79 | + private boolean registerKeepIntDialog = false; | |
| 80 | + | |
| 74 | 81 | public Boolean getSavePositionHistory() { |
| 75 | 82 | return savePositionHistory; |
| 76 | 83 | } |
| ... | ... | @@ -306,4 +313,36 @@ public class UserSetting { |
| 306 | 313 | public void setUseCustomSsrcForParentInvite(Boolean useCustomSsrcForParentInvite) { |
| 307 | 314 | this.useCustomSsrcForParentInvite = useCustomSsrcForParentInvite; |
| 308 | 315 | } |
| 316 | + | |
| 317 | + public Boolean getSqlLog() { | |
| 318 | + return sqlLog; | |
| 319 | + } | |
| 320 | + | |
| 321 | + public void setSqlLog(Boolean sqlLog) { | |
| 322 | + this.sqlLog = sqlLog; | |
| 323 | + } | |
| 324 | + | |
| 325 | + public String getCivilCodeFile() { | |
| 326 | + return civilCodeFile; | |
| 327 | + } | |
| 328 | + | |
| 329 | + public void setCivilCodeFile(String civilCodeFile) { | |
| 330 | + this.civilCodeFile = civilCodeFile; | |
| 331 | + } | |
| 332 | + | |
| 333 | + public int getRegisterAgainAfterTime() { | |
| 334 | + return registerAgainAfterTime; | |
| 335 | + } | |
| 336 | + | |
| 337 | + public void setRegisterAgainAfterTime(int registerAgainAfterTime) { | |
| 338 | + this.registerAgainAfterTime = registerAgainAfterTime; | |
| 339 | + } | |
| 340 | + | |
| 341 | + public boolean isRegisterKeepIntDialog() { | |
| 342 | + return registerKeepIntDialog; | |
| 343 | + } | |
| 344 | + | |
| 345 | + public void setRegisterKeepIntDialog(boolean registerKeepIntDialog) { | |
| 346 | + this.registerKeepIntDialog = registerKeepIntDialog; | |
| 347 | + } | |
| 309 | 348 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/VersionConfig.java
src/main/java/com/genersoft/iot/vmp/conf/redis/RedisMsgListenConfig.java
| ... | ... | @@ -43,6 +43,9 @@ public class RedisMsgListenConfig { |
| 43 | 43 | @Autowired |
| 44 | 44 | private RedisPushStreamResponseListener redisPushStreamResponseListener; |
| 45 | 45 | |
| 46 | + @Autowired | |
| 47 | + private RedisCloseStreamMsgListener redisCloseStreamMsgListener; | |
| 48 | + | |
| 46 | 49 | |
| 47 | 50 | /** |
| 48 | 51 | * redis消息监听器容器 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器 |
| ... | ... | @@ -63,6 +66,7 @@ public class RedisMsgListenConfig { |
| 63 | 66 | container.addMessageListener(redisPushStreamStatusMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_STATUS_CHANGE)); |
| 64 | 67 | container.addMessageListener(redisPushStreamListMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_LIST_CHANGE)); |
| 65 | 68 | container.addMessageListener(redisPushStreamResponseListener, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_RESPONSE)); |
| 69 | + container.addMessageListener(redisCloseStreamMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_CLOSE)); | |
| 66 | 70 | return container; |
| 67 | 71 | } |
| 68 | 72 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
| ... | ... | @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.conf.security; |
| 3 | 3 | import com.alibaba.fastjson2.JSONObject; |
| 4 | 4 | import com.genersoft.iot.vmp.conf.security.dto.JwtUser; |
| 5 | 5 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 6 | +import org.springframework.http.MediaType; | |
| 6 | 7 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
| 7 | 8 | import org.springframework.security.core.AuthenticationException; |
| 8 | 9 | import org.springframework.security.core.context.SecurityContextHolder; |
| ... | ... | @@ -12,6 +13,7 @@ import org.springframework.stereotype.Component; |
| 12 | 13 | import javax.servlet.http.HttpServletRequest; |
| 13 | 14 | import javax.servlet.http.HttpServletResponse; |
| 14 | 15 | import java.io.IOException; |
| 16 | +import java.nio.charset.StandardCharsets; | |
| 15 | 17 | |
| 16 | 18 | /** |
| 17 | 19 | * 处理匿名用户访问逻辑 |
| ... | ... | @@ -35,6 +37,8 @@ public class AnonymousAuthenticationEntryPoint implements AuthenticationEntry |
| 35 | 37 | jsonObject.put("msg", e.getMessage()); |
| 36 | 38 | } |
| 37 | 39 | response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); |
| 40 | + response.setContentType(MediaType.APPLICATION_JSON_VALUE); | |
| 41 | + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); | |
| 38 | 42 | try { |
| 39 | 43 | response.getWriter().print(jsonObject.toJSONString()); |
| 40 | 44 | } catch (IOException ioException) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
| 1 | 1 | package com.genersoft.iot.vmp.conf.security; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 4 | -import org.junit.jupiter.api.Order; | |
| 4 | +import org.springframework.core.annotation.Order; | |
| 5 | 5 | import org.slf4j.Logger; |
| 6 | 6 | import org.slf4j.LoggerFactory; |
| 7 | 7 | import org.springframework.beans.factory.annotation.Autowired; | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
| ... | ... | @@ -77,8 +77,8 @@ public class Device { |
| 77 | 77 | /** |
| 78 | 78 | * 在线 |
| 79 | 79 | */ |
| 80 | - @Schema(description = "是否在线,1为在线,0为离线") | |
| 81 | - private int online; | |
| 80 | + @Schema(description = "是否在线,true为在线,false为离线") | |
| 81 | + private boolean onLine; | |
| 82 | 82 | |
| 83 | 83 | |
| 84 | 84 | /** |
| ... | ... | @@ -140,7 +140,7 @@ public class Device { |
| 140 | 140 | /** |
| 141 | 141 | * 目录订阅周期,0为不订阅 |
| 142 | 142 | */ |
| 143 | - @Schema(description = "目录订阅周期,0为不订阅") | |
| 143 | + @Schema(description = "目录订阅周期,o为不订阅") | |
| 144 | 144 | private int subscribeCycleForCatalog; |
| 145 | 145 | |
| 146 | 146 | /** |
| ... | ... | @@ -173,12 +173,6 @@ public class Device { |
| 173 | 173 | @Schema(description = "地理坐标系, 目前支持 WGS84,GCJ02") |
| 174 | 174 | private String geoCoordSys; |
| 175 | 175 | |
| 176 | - /** | |
| 177 | - * 树类型 国标规定了两种树的展现方式 行政区划:CivilCode 和业务分组:BusinessGroup | |
| 178 | - */ | |
| 179 | - @Schema(description = "树类型 国标规定了两种树的展现方式 行政区划:CivilCode 和业务分组:BusinessGroup") | |
| 180 | - private String treeType; | |
| 181 | - | |
| 182 | 176 | @Schema(description = "密码") |
| 183 | 177 | private String password; |
| 184 | 178 | |
| ... | ... | @@ -195,6 +189,8 @@ public class Device { |
| 195 | 189 | private SipTransactionInfo sipTransactionInfo; |
| 196 | 190 | |
| 197 | 191 | |
| 192 | + | |
| 193 | + | |
| 198 | 194 | public String getDeviceId() { |
| 199 | 195 | return deviceId; |
| 200 | 196 | } |
| ... | ... | @@ -286,12 +282,12 @@ public class Device { |
| 286 | 282 | this.hostAddress = hostAddress; |
| 287 | 283 | } |
| 288 | 284 | |
| 289 | - public int getOnline() { | |
| 290 | - return online; | |
| 285 | + public boolean isOnLine() { | |
| 286 | + return onLine; | |
| 291 | 287 | } |
| 292 | 288 | |
| 293 | - public void setOnline(int online) { | |
| 294 | - this.online = online; | |
| 289 | + public void setOnLine(boolean onLine) { | |
| 290 | + this.onLine = onLine; | |
| 295 | 291 | } |
| 296 | 292 | |
| 297 | 293 | public int getChannelCount() { |
| ... | ... | @@ -406,15 +402,6 @@ public class Device { |
| 406 | 402 | this.geoCoordSys = geoCoordSys; |
| 407 | 403 | } |
| 408 | 404 | |
| 409 | - | |
| 410 | - public String getTreeType() { | |
| 411 | - return treeType; | |
| 412 | - } | |
| 413 | - | |
| 414 | - public void setTreeType(String treeType) { | |
| 415 | - this.treeType = treeType; | |
| 416 | - } | |
| 417 | - | |
| 418 | 405 | public String getPassword() { |
| 419 | 406 | return password; |
| 420 | 407 | } |
| ... | ... | @@ -462,4 +449,20 @@ public class Device { |
| 462 | 449 | public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) { |
| 463 | 450 | this.sipTransactionInfo = sipTransactionInfo; |
| 464 | 451 | } |
| 452 | + | |
| 453 | + /*======================设备主子码流逻辑START=========================*/ | |
| 454 | + @Schema(description = "开启主子码流切换的开关(false-不开启,true-开启)") | |
| 455 | + private boolean switchPrimarySubStream; | |
| 456 | + | |
| 457 | + public boolean isSwitchPrimarySubStream() { | |
| 458 | + return switchPrimarySubStream; | |
| 459 | + } | |
| 460 | + | |
| 461 | + public void setSwitchPrimarySubStream(boolean switchPrimarySubStream) { | |
| 462 | + this.switchPrimarySubStream = switchPrimarySubStream; | |
| 463 | + } | |
| 464 | + | |
| 465 | + /*======================设备主子码流逻辑END=========================*/ | |
| 466 | + | |
| 467 | + | |
| 465 | 468 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
| ... | ... | @@ -172,7 +172,7 @@ public class DeviceChannel { |
| 172 | 172 | * 遇到过NVR下的IPC下发信令可以推流, 但是 Status 响应 OFF |
| 173 | 173 | */ |
| 174 | 174 | @Schema(description = "在线/离线, 1在线,0离线") |
| 175 | - private int status; | |
| 175 | + private boolean status; | |
| 176 | 176 | |
| 177 | 177 | /** |
| 178 | 178 | * 经度 |
| ... | ... | @@ -455,11 +455,11 @@ public class DeviceChannel { |
| 455 | 455 | this.PTZTypeText = PTZTypeText; |
| 456 | 456 | } |
| 457 | 457 | |
| 458 | - public int getStatus() { | |
| 458 | + public boolean isStatus() { | |
| 459 | 459 | return status; |
| 460 | 460 | } |
| 461 | 461 | |
| 462 | - public void setStatus(int status) { | |
| 462 | + public void setStatus(boolean status) { | |
| 463 | 463 | this.status = status; |
| 464 | 464 | } |
| 465 | 465 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Gb28181Sdp.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.gb28181.bean; | |
| 2 | + | |
| 3 | +import javax.sdp.SessionDescription; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 28181 的SDP解析器 | |
| 7 | + */ | |
| 8 | +public class Gb28181Sdp { | |
| 9 | + private SessionDescription baseSdb; | |
| 10 | + private String ssrc; | |
| 11 | + | |
| 12 | + private String mediaDescription; | |
| 13 | + | |
| 14 | + public static Gb28181Sdp getInstance(SessionDescription baseSdb, String ssrc, String mediaDescription) { | |
| 15 | + Gb28181Sdp gb28181Sdp = new Gb28181Sdp(); | |
| 16 | + gb28181Sdp.setBaseSdb(baseSdb); | |
| 17 | + gb28181Sdp.setSsrc(ssrc); | |
| 18 | + gb28181Sdp.setMediaDescription(mediaDescription); | |
| 19 | + return gb28181Sdp; | |
| 20 | + } | |
| 21 | + | |
| 22 | + | |
| 23 | + public SessionDescription getBaseSdb() { | |
| 24 | + return baseSdb; | |
| 25 | + } | |
| 26 | + | |
| 27 | + public void setBaseSdb(SessionDescription baseSdb) { | |
| 28 | + this.baseSdb = baseSdb; | |
| 29 | + } | |
| 30 | + | |
| 31 | + public String getSsrc() { | |
| 32 | + return ssrc; | |
| 33 | + } | |
| 34 | + | |
| 35 | + public void setSsrc(String ssrc) { | |
| 36 | + this.ssrc = ssrc; | |
| 37 | + } | |
| 38 | + | |
| 39 | + public String getMediaDescription() { | |
| 40 | + return mediaDescription; | |
| 41 | + } | |
| 42 | + | |
| 43 | + public void setMediaDescription(String mediaDescription) { | |
| 44 | + this.mediaDescription = mediaDescription; | |
| 45 | + } | |
| 46 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java
| ... | ... | @@ -10,7 +10,7 @@ import io.swagger.v3.oas.annotations.media.Schema; |
| 10 | 10 | public class GbStream extends PlatformGbStream{ |
| 11 | 11 | |
| 12 | 12 | @Schema(description = "ID") |
| 13 | - private Integer gbStreamId; | |
| 13 | + private int gbStreamId; | |
| 14 | 14 | @Schema(description = "应用名") |
| 15 | 15 | private String app; |
| 16 | 16 | @Schema(description = "流ID") | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
| ... | ... | @@ -183,12 +183,6 @@ public class ParentPlatform { |
| 183 | 183 | @Schema(description = "创建时间") |
| 184 | 184 | private String createTime; |
| 185 | 185 | |
| 186 | - /** | |
| 187 | - * 树类型 国标规定了两种树的展现方式 行政区划 CivilCode 和业务分组:BusinessGroup | |
| 188 | - */ | |
| 189 | - @Schema(description = "树类型 国标规定了两种树的展现方式 行政区划 CivilCode 和业务分组:BusinessGrou") | |
| 190 | - private String treeType; | |
| 191 | - | |
| 192 | 186 | @Schema(description = "是否作为消息通道") |
| 193 | 187 | private boolean asMessageChannel; |
| 194 | 188 | |
| ... | ... | @@ -424,14 +418,6 @@ public class ParentPlatform { |
| 424 | 418 | this.createTime = createTime; |
| 425 | 419 | } |
| 426 | 420 | |
| 427 | - public String getTreeType() { | |
| 428 | - return treeType; | |
| 429 | - } | |
| 430 | - | |
| 431 | - public void setTreeType(String treeType) { | |
| 432 | - this.treeType = treeType; | |
| 433 | - } | |
| 434 | - | |
| 435 | 421 | public boolean isAsMessageChannel() { |
| 436 | 422 | return asMessageChannel; |
| 437 | 423 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java
src/main/java/com/genersoft/iot/vmp/gb28181/bean/TreeType.java deleted
100644 → 0
src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181.session; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 4 | +import com.genersoft.iot.vmp.conf.UserSetting; | |
| 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; |
| 5 | 6 | import org.springframework.data.redis.core.StringRedisTemplate; |
| 6 | 7 | import org.springframework.stereotype.Component; |
| ... | ... | @@ -31,10 +32,13 @@ public class SSRCFactory { |
| 31 | 32 | @Autowired |
| 32 | 33 | private SipConfig sipConfig; |
| 33 | 34 | |
| 35 | + @Autowired | |
| 36 | + private UserSetting userSetting; | |
| 37 | + | |
| 34 | 38 | |
| 35 | 39 | public void initMediaServerSSRC(String mediaServerId, Set<String> usedSet) { |
| 36 | 40 | String ssrcPrefix = sipConfig.getDomain().substring(3, 8); |
| 37 | - String redisKey = SSRC_INFO_KEY + mediaServerId; | |
| 41 | + String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId; | |
| 38 | 42 | List<String> ssrcList = new ArrayList<>(); |
| 39 | 43 | for (int i = 1; i < MAX_STREAM_COUNT; i++) { |
| 40 | 44 | String ssrc = String.format("%s%04d", ssrcPrefix, i); |
| ... | ... | @@ -77,7 +81,7 @@ public class SSRCFactory { |
| 77 | 81 | return; |
| 78 | 82 | } |
| 79 | 83 | String sn = ssrc.substring(1); |
| 80 | - String redisKey = SSRC_INFO_KEY + mediaServerId; | |
| 84 | + String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId; | |
| 81 | 85 | redisTemplate.opsForSet().add(redisKey, sn); |
| 82 | 86 | } |
| 83 | 87 | |
| ... | ... | @@ -86,7 +90,7 @@ public class SSRCFactory { |
| 86 | 90 | */ |
| 87 | 91 | private String getSN(String mediaServerId) { |
| 88 | 92 | String sn = null; |
| 89 | - String redisKey = SSRC_INFO_KEY + mediaServerId; | |
| 93 | + String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId; | |
| 90 | 94 | Long size = redisTemplate.opsForSet().size(redisKey); |
| 91 | 95 | if (size == null || size == 0) { |
| 92 | 96 | throw new RuntimeException("ssrc已经用完"); |
| ... | ... | @@ -113,20 +117,8 @@ public class SSRCFactory { |
| 113 | 117 | * @param mediaServerId 流媒体服务ID |
| 114 | 118 | */ |
| 115 | 119 | public boolean hasMediaServerSSRC(String mediaServerId) { |
| 116 | - String redisKey = SSRC_INFO_KEY + mediaServerId; | |
| 120 | + String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId; | |
| 117 | 121 | return redisTemplate.opsForSet().members(redisKey) != null; |
| 118 | 122 | } |
| 119 | 123 | |
| 120 | - /** | |
| 121 | - * 查询ssrc是否可用 | |
| 122 | - * | |
| 123 | - * @param mediaServerId | |
| 124 | - * @param ssrc | |
| 125 | - * @return | |
| 126 | - */ | |
| 127 | - public boolean checkSsrc(String mediaServerId, String ssrc) { | |
| 128 | - String sn = ssrc.substring(1); | |
| 129 | - String redisKey = SSRC_INFO_KEY + mediaServerId; | |
| 130 | - return redisTemplate.opsForSet().isMember(redisKey, sn) != null; | |
| 131 | - } | |
| 132 | 124 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
| ... | ... | @@ -39,16 +39,22 @@ public class DeferredResultHolder { |
| 39 | 39 | |
| 40 | 40 | public static final String CALLBACK_CMD_DOWNLOAD = "CALLBACK_DOWNLOAD"; |
| 41 | 41 | |
| 42 | + public static final String CALLBACK_CMD_PROXY = "CALLBACK_PROXY"; | |
| 43 | + | |
| 42 | 44 | public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP"; |
| 43 | 45 | |
| 44 | 46 | public static final String UPLOAD_FILE_CHANNEL = "UPLOAD_FILE_CHANNEL"; |
| 45 | 47 | |
| 46 | - public static final String CALLBACK_CMD_MOBILEPOSITION = "CALLBACK_MOBILEPOSITION"; | |
| 48 | + public static final String CALLBACK_CMD_MOBILE_POSITION = "CALLBACK_CMD_MOBILE_POSITION"; | |
| 47 | 49 | |
| 48 | 50 | public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY"; |
| 49 | 51 | |
| 50 | 52 | public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM"; |
| 51 | 53 | |
| 54 | + public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST"; | |
| 55 | + | |
| 56 | + public static final String CALLBACK_CMD_SNAP= "CALLBACK_SNAP"; | |
| 57 | + | |
| 52 | 58 | private Map<String, Map<String, DeferredResultEx>> map = new ConcurrentHashMap<>(); |
| 53 | 59 | |
| 54 | 60 | |
| ... | ... | @@ -149,4 +155,6 @@ public class DeferredResultHolder { |
| 149 | 155 | map.remove(msg.getKey()); |
| 150 | 156 | } |
| 151 | 157 | } |
| 158 | + | |
| 159 | + | |
| 152 | 160 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
| ... | ... | @@ -80,7 +80,7 @@ public interface ISIPCommanderForPlatform { |
| 80 | 80 | * @param fromTag |
| 81 | 81 | * @return |
| 82 | 82 | */ |
| 83 | - void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,int status) throws SipException, InvalidArgumentException, ParseException ; | |
| 83 | + void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,boolean status) throws SipException, InvalidArgumentException, ParseException; | |
| 84 | 84 | |
| 85 | 85 | /** |
| 86 | 86 | * 向上级回复移动位置订阅消息 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
| ... | ... | @@ -55,8 +55,8 @@ public class SIPRequestHeaderPlarformProvider { |
| 55 | 55 | parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort()); |
| 56 | 56 | //via |
| 57 | 57 | ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); |
| 58 | - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getServerIP(), | |
| 59 | - parentPlatform.getServerPort(), parentPlatform.getTransport(), SipUtils.getNewViaTag()); | |
| 58 | + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), | |
| 59 | + Integer.parseInt(parentPlatform.getDevicePort()), parentPlatform.getTransport(), SipUtils.getNewViaTag()); | |
| 60 | 60 | viaHeader.setRPort(); |
| 61 | 61 | viaHeaders.add(viaHeader); |
| 62 | 62 | //from | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; |
| 2 | 2 | |
| 3 | -import com.alibaba.fastjson2.JSONObject; | |
| 4 | 3 | import com.genersoft.iot.vmp.common.InviteSessionType; |
| 5 | 4 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 6 | 5 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 7 | 6 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 8 | 7 | import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; |
| 9 | 8 | import com.genersoft.iot.vmp.gb28181.SipLayer; |
| 10 | -import com.genersoft.iot.vmp.gb28181.bean.*; | |
| 9 | +import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 10 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; | |
| 11 | +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; | |
| 11 | 12 | import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
| 12 | 13 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| 13 | 14 | import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; |
| ... | ... | @@ -21,6 +22,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; |
| 21 | 22 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; |
| 22 | 23 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamPush; |
| 23 | 24 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 25 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; | |
| 24 | 26 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 25 | 27 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| 26 | 28 | import com.genersoft.iot.vmp.utils.DateUtil; |
| ... | ... | @@ -155,6 +157,11 @@ public class SIPCommander implements ISIPCommander { |
| 155 | 157 | builder.append(strTmp, 0, 2); |
| 156 | 158 | strTmp = String.format("%02X", parameter2); |
| 157 | 159 | builder.append(strTmp, 0, 2); |
| 160 | + //优化zoom变倍速率 | |
| 161 | + if ((combineCode2 > 0) && (combineCode2 <16)) | |
| 162 | + { | |
| 163 | + combineCode2 = 16; | |
| 164 | + } | |
| 158 | 165 | strTmp = String.format("%X", combineCode2); |
| 159 | 166 | builder.append(strTmp, 0, 1).append("0"); |
| 160 | 167 | //计算校验码 |
| ... | ... | @@ -280,9 +287,9 @@ public class SIPCommander implements ISIPCommander { |
| 280 | 287 | |
| 281 | 288 | logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort()); |
| 282 | 289 | HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId()); |
| 283 | - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { | |
| 290 | + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> { | |
| 284 | 291 | if (event != null) { |
| 285 | - event.response(mediaServerItemInUse, json); | |
| 292 | + event.response(mediaServerItemInUse, hookParam); | |
| 286 | 293 | subscribe.removeSubscribe(hookSubscribe); |
| 287 | 294 | } |
| 288 | 295 | }); |
| ... | ... | @@ -345,6 +352,22 @@ public class SIPCommander implements ISIPCommander { |
| 345 | 352 | } |
| 346 | 353 | } |
| 347 | 354 | |
| 355 | + if( device.isSwitchPrimarySubStream() ){ | |
| 356 | + if("TP-LINK".equals(device.getManufacturer())){ | |
| 357 | + if (device.isSwitchPrimarySubStream()){ | |
| 358 | + content.append("a=streamMode:sub\r\n"); | |
| 359 | + }else { | |
| 360 | + content.append("a=streamMode:main\r\n"); | |
| 361 | + } | |
| 362 | + }else { | |
| 363 | + if (device.isSwitchPrimarySubStream()){ | |
| 364 | + content.append("a=streamprofile:1\r\n"); | |
| 365 | + }else { | |
| 366 | + content.append("a=streamprofile:0\r\n"); | |
| 367 | + } | |
| 368 | + } | |
| 369 | + } | |
| 370 | + | |
| 348 | 371 | content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc |
| 349 | 372 | // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率 |
| 350 | 373 | // content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备 |
| ... | ... | @@ -360,7 +383,8 @@ public class SIPCommander implements ISIPCommander { |
| 360 | 383 | // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值 |
| 361 | 384 | ResponseEvent responseEvent = (ResponseEvent) e.event; |
| 362 | 385 | SIPResponse response = (SIPResponse) responseEvent.getResponse(); |
| 363 | - streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAY); | |
| 386 | + streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, | |
| 387 | + InviteSessionType.PLAY); | |
| 364 | 388 | okEvent.response(e); |
| 365 | 389 | }); |
| 366 | 390 | } |
| ... | ... | @@ -450,13 +474,13 @@ public class SIPCommander implements ISIPCommander { |
| 450 | 474 | |
| 451 | 475 | HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); |
| 452 | 476 | // 添加订阅 |
| 453 | - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { | |
| 477 | + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> { | |
| 454 | 478 | if (hookEvent != null) { |
| 455 | - hookEvent.response(mediaServerItemInUse, json); | |
| 479 | + hookEvent.response(mediaServerItemInUse, hookParam); | |
| 456 | 480 | } |
| 457 | 481 | subscribe.removeSubscribe(hookSubscribe); |
| 458 | 482 | }); |
| 459 | - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc()); | |
| 483 | + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc()); | |
| 460 | 484 | |
| 461 | 485 | sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { |
| 462 | 486 | ResponseEvent responseEvent = (ResponseEvent) event.event; |
| ... | ... | @@ -553,15 +577,15 @@ public class SIPCommander implements ISIPCommander { |
| 553 | 577 | // 添加订阅 |
| 554 | 578 | CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()); |
| 555 | 579 | String callId= newCallIdHeader.getCallId(); |
| 556 | - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { | |
| 580 | + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> { | |
| 557 | 581 | logger.debug("sipc 添加订阅===callId {}",callId); |
| 558 | - hookEvent.response(mediaServerItemInUse, json); | |
| 582 | + hookEvent.response(mediaServerItemInUse, hookParam); | |
| 559 | 583 | subscribe.removeSubscribe(hookSubscribe); |
| 560 | 584 | hookSubscribe.getContent().put("regist", false); |
| 561 | 585 | hookSubscribe.getContent().put("schema", "rtsp"); |
| 562 | 586 | // 添加流注销的订阅,注销了后向设备发送bye |
| 563 | 587 | subscribe.addSubscribe(hookSubscribe, |
| 564 | - (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd) -> { | |
| 588 | + (mediaServerItemForEnd, hookParam1) -> { | |
| 565 | 589 | logger.info("[录像]下载结束, 发送BYE"); |
| 566 | 590 | try { |
| 567 | 591 | streamByeCmd(device, channelId, ssrcInfo.getStream(), callId); |
| ... | ... | @@ -572,17 +596,13 @@ public class SIPCommander implements ISIPCommander { |
| 572 | 596 | }); |
| 573 | 597 | }); |
| 574 | 598 | |
| 575 | - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc()); | |
| 599 | + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc()); | |
| 576 | 600 | |
| 577 | 601 | sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> { |
| 578 | 602 | ResponseEvent responseEvent = (ResponseEvent) event.event; |
| 579 | 603 | SIPResponse response = (SIPResponse) responseEvent.getResponse(); |
| 580 | 604 | String contentString =new String(response.getRawContent()); |
| 581 | - int ssrcIndex = contentString.indexOf("y="); | |
| 582 | - String ssrc=ssrcInfo.getSsrc(); | |
| 583 | - if (ssrcIndex >= 0) { | |
| 584 | - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); | |
| 585 | - } | |
| 605 | + String ssrc = SipUtils.getSsrcFromSdp(contentString); | |
| 586 | 606 | streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD); |
| 587 | 607 | okEvent.response(event); |
| 588 | 608 | }); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
| ... | ... | @@ -230,59 +230,150 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 230 | 230 | // 行政区划分组只需要这两项就可以 |
| 231 | 231 | catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n"); |
| 232 | 232 | catalogXml.append("<Name>" + channel.getName() + "</Name>\r\n"); |
| 233 | - if (channel.getParentId() != null) { | |
| 234 | - // 业务分组加上这一项即可,提高兼容性, | |
| 235 | - catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n"); | |
| 236 | -// catalogXml.append("<ParentID>" + parentPlatform.getDeviceGBId() + "/" + channel.getParentId() + "</ParentID>\r\n"); | |
| 237 | - } | |
| 238 | - if (channel.getChannelId().length() == 20 && Integer.parseInt(channel.getChannelId().substring(10, 13)) == 216) { | |
| 239 | - // 虚拟组织增加BusinessGroupID字段 | |
| 240 | - catalogXml.append("<BusinessGroupID>" + channel.getParentId() + "</BusinessGroupID>\r\n"); | |
| 241 | - } | |
| 242 | - if (!channel.getChannelId().equals(parentPlatform.getDeviceGBId())) { | |
| 243 | - catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n"); | |
| 244 | - if (channel.getParental() == 0) { | |
| 245 | - catalogXml.append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n"); | |
| 233 | + if (channel.getChannelId().length() <= 8) { | |
| 234 | + catalogXml.append("</Item>\r\n"); | |
| 235 | + continue; | |
| 236 | + }else { | |
| 237 | + if (channel.getChannelId().length() != 20) { | |
| 238 | + catalogXml.append("</Item>\r\n"); | |
| 239 | + continue; | |
| 246 | 240 | } |
| 247 | - } | |
| 248 | - if (channel.getParental() == 0) { | |
| 249 | - // 通道项 | |
| 250 | - catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n"); | |
| 251 | - catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n"); | |
| 252 | - catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n"); | |
| 253 | - String civilCode = channel.getCivilCode() == null?parentPlatform.getAdministrativeDivision() : channel.getCivilCode(); | |
| 254 | - if (channel.getChannelType() != 2) { // 业务分组/虚拟组织/行政区划 不设置以下属性 | |
| 255 | - catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n"); | |
| 256 | - catalogXml.append("<Owner>" + parentPlatform.getDeviceGBId()+ "</Owner>\r\n"); | |
| 257 | - catalogXml.append("<CivilCode>" + civilCode + "</CivilCode>\r\n"); | |
| 258 | - if (channel.getAddress() == null) { | |
| 259 | - catalogXml.append("<Address></Address>\r\n"); | |
| 260 | - }else { | |
| 261 | - catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n"); | |
| 262 | - } | |
| 263 | - catalogXml.append("<Block>" + channel.getBlock() + "</Block>\r\n"); | |
| 264 | - catalogXml.append("<SafetyWay>" + channel.getSafetyWay() + "</SafetyWay>\r\n"); | |
| 265 | - catalogXml.append("<CertNum>" + channel.getCertNum() + "</CertNum>\r\n"); | |
| 266 | - catalogXml.append("<Certifiable>" + channel.getCertifiable() + "</Certifiable>\r\n"); | |
| 267 | - catalogXml.append("<ErrCode>" + channel.getErrCode() + "</ErrCode>\r\n"); | |
| 268 | - catalogXml.append("<EndTime>" + channel.getEndTime() + "</EndTime>\r\n"); | |
| 269 | - catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n"); | |
| 270 | - catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n"); | |
| 271 | - catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n"); | |
| 272 | - catalogXml.append("<Password>" + channel.getPort() + "</Password>\r\n"); | |
| 273 | - catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n"); | |
| 274 | - catalogXml.append("<Status>" + (channel.getStatus() == 1?"ON":"OFF") + "</Status>\r\n"); | |
| 275 | - catalogXml.append("<Longitude>" + | |
| 276 | - (channel.getLongitudeWgs84() != 0? channel.getLongitudeWgs84():channel.getLongitude()) | |
| 277 | - + "</Longitude>\r\n"); | |
| 278 | - catalogXml.append("<Latitude>" + | |
| 279 | - (channel.getLatitudeWgs84() != 0? channel.getLatitudeWgs84():channel.getLatitude()) | |
| 280 | - + "</Latitude>\r\n"); | |
| 281 | - | |
| 241 | + switch (Integer.parseInt(channel.getChannelId().substring(10, 13))){ | |
| 242 | + case 200: | |
| 243 | +// catalogXml.append("<Manufacturer>三永华通</Manufacturer>\r\n"); | |
| 244 | +// GitUtil gitUtil = SpringBeanFactory.getBean("gitUtil"); | |
| 245 | +// String model = (gitUtil == null || gitUtil.getBuildVersion() == null)?"1.0": gitUtil.getBuildVersion(); | |
| 246 | +// catalogXml.append("<Model>" + model + "</Manufacturer>\r\n"); | |
| 247 | +// catalogXml.append("<Owner>三永华通</Owner>\r\n"); | |
| 248 | + if (channel.getCivilCode() != null) { | |
| 249 | + catalogXml.append("<CivilCode>"+channel.getCivilCode()+"</CivilCode>\r\n"); | |
| 250 | + }else { | |
| 251 | + catalogXml.append("<CivilCode></CivilCode>\r\n"); | |
| 252 | + } | |
| 253 | + | |
| 254 | + catalogXml.append("<RegisterWay>1</RegisterWay>\r\n"); | |
| 255 | + catalogXml.append("<Secrecy>0</Secrecy>\r\n"); | |
| 256 | + break; | |
| 257 | + case 215: | |
| 258 | + if (!ObjectUtils.isEmpty(channel.getParentId())) { | |
| 259 | + catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n"); | |
| 260 | + } | |
| 261 | + | |
| 262 | + break; | |
| 263 | + case 216: | |
| 264 | + if (!ObjectUtils.isEmpty(channel.getParentId())) { | |
| 265 | + catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n"); | |
| 266 | + }else { | |
| 267 | + catalogXml.append("<ParentID></ParentID>\r\n"); | |
| 268 | + } | |
| 269 | + if (!ObjectUtils.isEmpty(channel.getBusinessGroupId())) { | |
| 270 | + catalogXml.append("<BusinessGroupID>" + channel.getBusinessGroupId() + "</BusinessGroupID>\r\n"); | |
| 271 | + }else { | |
| 272 | + catalogXml.append("<BusinessGroupID></BusinessGroupID>\r\n"); | |
| 273 | + } | |
| 274 | + break; | |
| 275 | + default: | |
| 276 | + // 通道项 | |
| 277 | + if (channel.getManufacture() != null) { | |
| 278 | + catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n"); | |
| 279 | + }else { | |
| 280 | + catalogXml.append("<Manufacturer></Manufacturer>\r\n"); | |
| 281 | + } | |
| 282 | + if (channel.getSecrecy() != null) { | |
| 283 | + catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n"); | |
| 284 | + }else { | |
| 285 | + catalogXml.append("<Secrecy></Secrecy>\r\n"); | |
| 286 | + } | |
| 287 | + catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n"); | |
| 288 | + if (channel.getModel() != null) { | |
| 289 | + catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n"); | |
| 290 | + }else { | |
| 291 | + catalogXml.append("<Model></Model>\r\n"); | |
| 292 | + } | |
| 293 | + if (channel.getOwner() != null) { | |
| 294 | + catalogXml.append("<Owner>" + channel.getOwner()+ "</Owner>\r\n"); | |
| 295 | + }else { | |
| 296 | + catalogXml.append("<Owner></Owner>\r\n"); | |
| 297 | + } | |
| 298 | + if (channel.getCivilCode() != null) { | |
| 299 | + catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n"); | |
| 300 | + }else { | |
| 301 | + catalogXml.append("<CivilCode></CivilCode>\r\n"); | |
| 302 | + } | |
| 303 | + if (channel.getAddress() == null) { | |
| 304 | + catalogXml.append("<Address></Address>\r\n"); | |
| 305 | + }else { | |
| 306 | + catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n"); | |
| 307 | + } | |
| 308 | + if (!ObjectUtils.isEmpty(channel.getParentId())) { | |
| 309 | + catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n"); | |
| 310 | + }else { | |
| 311 | + catalogXml.append("<ParentID></ParentID>\r\n"); | |
| 312 | + } | |
| 313 | + if (!ObjectUtils.isEmpty(channel.getBlock())) { | |
| 314 | + catalogXml.append("<Block>" + channel.getBlock() + "</Block>\r\n"); | |
| 315 | + }else { | |
| 316 | + catalogXml.append("<Block></Block>\r\n"); | |
| 317 | + } | |
| 318 | + if (!ObjectUtils.isEmpty(channel.getSafetyWay())) { | |
| 319 | + catalogXml.append("<SafetyWay>" + channel.getSafetyWay() + "</SafetyWay>\r\n"); | |
| 320 | + }else { | |
| 321 | + catalogXml.append("<SafetyWay></SafetyWay>\r\n"); | |
| 322 | + } | |
| 323 | + if (!ObjectUtils.isEmpty(channel.getCertNum())) { | |
| 324 | + catalogXml.append("<CertNum>" + channel.getCertNum() + "</CertNum>\r\n"); | |
| 325 | + }else { | |
| 326 | + catalogXml.append("<CertNum></CertNum>\r\n"); | |
| 327 | + } | |
| 328 | + if (!ObjectUtils.isEmpty(channel.getCertifiable())) { | |
| 329 | + catalogXml.append("<Certifiable>" + channel.getCertifiable() + "</Certifiable>\r\n"); | |
| 330 | + }else { | |
| 331 | + catalogXml.append("<Certifiable></Certifiable>\r\n"); | |
| 332 | + } | |
| 333 | + if (!ObjectUtils.isEmpty(channel.getErrCode())) { | |
| 334 | + catalogXml.append("<ErrCode>" + channel.getErrCode() + "</ErrCode>\r\n"); | |
| 335 | + }else { | |
| 336 | + catalogXml.append("<ErrCode></ErrCode>\r\n"); | |
| 337 | + } | |
| 338 | + if (!ObjectUtils.isEmpty(channel.getEndTime())) { | |
| 339 | + catalogXml.append("<EndTime>" + channel.getEndTime() + "</EndTime>\r\n"); | |
| 340 | + }else { | |
| 341 | + catalogXml.append("<EndTime></EndTime>\r\n"); | |
| 342 | + } | |
| 343 | + if (!ObjectUtils.isEmpty(channel.getSecrecy())) { | |
| 344 | + catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n"); | |
| 345 | + }else { | |
| 346 | + catalogXml.append("<Secrecy></Secrecy>\r\n"); | |
| 347 | + } | |
| 348 | + if (!ObjectUtils.isEmpty(channel.getIpAddress())) { | |
| 349 | + catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n"); | |
| 350 | + }else { | |
| 351 | + catalogXml.append("<IPAddress></IPAddress>\r\n"); | |
| 352 | + } | |
| 353 | + catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n"); | |
| 354 | + if (!ObjectUtils.isEmpty(channel.getPassword())) { | |
| 355 | + catalogXml.append("<Password>" + channel.getPassword() + "</Password>\r\n"); | |
| 356 | + }else { | |
| 357 | + catalogXml.append("<Password></Password>\r\n"); | |
| 358 | + } | |
| 359 | + if (!ObjectUtils.isEmpty(channel.getPTZType())) { | |
| 360 | + catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n"); | |
| 361 | + }else { | |
| 362 | + catalogXml.append("<PTZType></PTZType>\r\n"); | |
| 363 | + } | |
| 364 | + catalogXml.append("<Status>" + (channel.isStatus() ?"ON":"OFF") + "</Status>\r\n"); | |
| 365 | + | |
| 366 | + catalogXml.append("<Longitude>" + | |
| 367 | + (channel.getLongitudeWgs84() != 0? channel.getLongitudeWgs84():channel.getLongitude()) | |
| 368 | + + "</Longitude>\r\n"); | |
| 369 | + catalogXml.append("<Latitude>" + | |
| 370 | + (channel.getLatitudeWgs84() != 0? channel.getLatitudeWgs84():channel.getLatitude()) | |
| 371 | + + "</Latitude>\r\n"); | |
| 372 | + break; | |
| 282 | 373 | |
| 283 | 374 | } |
| 375 | + catalogXml.append("</Item>\r\n"); | |
| 284 | 376 | } |
| 285 | - catalogXml.append("</Item>\r\n"); | |
| 286 | 377 | } |
| 287 | 378 | } |
| 288 | 379 | |
| ... | ... | @@ -399,11 +490,11 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 399 | 490 | * @return |
| 400 | 491 | */ |
| 401 | 492 | @Override |
| 402 | - public void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,int status) throws SipException, InvalidArgumentException, ParseException { | |
| 493 | + public void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,boolean status) throws SipException, InvalidArgumentException, ParseException { | |
| 403 | 494 | if (parentPlatform == null) { |
| 404 | 495 | return ; |
| 405 | 496 | } |
| 406 | - String statusStr = (status==1)?"ONLINE":"OFFLINE"; | |
| 497 | + String statusStr = (status)?"ONLINE":"OFFLINE"; | |
| 407 | 498 | String characterSet = parentPlatform.getCharacterSet(); |
| 408 | 499 | StringBuffer deviceStatusXml = new StringBuffer(600); |
| 409 | 500 | deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n") |
| ... | ... | @@ -564,7 +655,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 564 | 655 | catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n") |
| 565 | 656 | .append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n") |
| 566 | 657 | .append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n") |
| 567 | - .append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n"); | |
| 658 | + .append("<Status>" + (channel.isStatus() ? "ON" : "OFF") + "</Status>\r\n"); | |
| 568 | 659 | |
| 569 | 660 | if (channel.getChannelType() != 2) { // 业务分组/虚拟组织/行政区划 不设置以下属性 |
| 570 | 661 | catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n") | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
| ... | ... | @@ -166,9 +166,8 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In |
| 166 | 166 | streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlay.getStream()); |
| 167 | 167 | } |
| 168 | 168 | InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId); |
| 169 | - | |
| 169 | + inviteStreamService.removeInviteInfo(inviteInfo); | |
| 170 | 170 | if (inviteInfo != null) { |
| 171 | - inviteStreamService.removeInviteInfo(inviteInfo); | |
| 172 | 171 | if (inviteInfo.getStreamInfo() != null) { |
| 173 | 172 | mediaServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServerId(), inviteInfo.getStream()); |
| 174 | 173 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
| ... | ... | @@ -22,11 +22,12 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| 22 | 22 | import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; |
| 23 | 23 | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; |
| 24 | 24 | import com.genersoft.iot.vmp.media.zlm.dto.*; |
| 25 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; | |
| 25 | 26 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 26 | 27 | import com.genersoft.iot.vmp.service.IPlayService; |
| 27 | 28 | import com.genersoft.iot.vmp.service.IStreamProxyService; |
| 28 | 29 | import com.genersoft.iot.vmp.service.IStreamPushService; |
| 29 | -import com.genersoft.iot.vmp.service.bean.InviteErrorCallback; | |
| 30 | +import com.genersoft.iot.vmp.service.bean.ErrorCallback; | |
| 30 | 31 | import com.genersoft.iot.vmp.service.bean.InviteErrorCode; |
| 31 | 32 | import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; |
| 32 | 33 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| ... | ... | @@ -217,6 +218,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 217 | 218 | logger.error("[命令发送失败] invite GONE: {}", e.getMessage()); |
| 218 | 219 | } |
| 219 | 220 | return; |
| 221 | + }else { | |
| 222 | + // TODO 可能漏回复消息 | |
| 220 | 223 | } |
| 221 | 224 | } |
| 222 | 225 | } else { |
| ... | ... | @@ -270,18 +273,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 270 | 273 | // 解析sdp消息, 使用jainsip 自带的sdp解析方式 |
| 271 | 274 | String contentString = new String(request.getRawContent()); |
| 272 | 275 | |
| 273 | - // jainSip不支持y=字段, 移除以解析。 | |
| 274 | - // 检查是否有y字段 | |
| 275 | - int ssrcIndex = contentString.indexOf("y="); | |
| 276 | - | |
| 277 | - SessionDescription sdp; | |
| 278 | - if (ssrcIndex >= 0) { | |
| 279 | - //ssrc规定长度为10个字节,不取余下长度以避免后续还有“f=”字段 | |
| 280 | - String substring = contentString.substring(0, ssrcIndex); | |
| 281 | - sdp = SdpFactory.getInstance().createSessionDescription(substring); | |
| 282 | - } else { | |
| 283 | - sdp = SdpFactory.getInstance().createSessionDescription(contentString); | |
| 284 | - } | |
| 276 | + Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString); | |
| 277 | + SessionDescription sdp = gb28181Sdp.getBaseSdb(); | |
| 285 | 278 | String sessionName = sdp.getSessionName().getValue(); |
| 286 | 279 | |
| 287 | 280 | Long startTime = null; |
| ... | ... | @@ -369,11 +362,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 369 | 362 | } |
| 370 | 363 | |
| 371 | 364 | String ssrc; |
| 372 | - if (userSetting.getUseCustomSsrcForParentInvite() || ssrcIndex < 0) { | |
| 365 | + if (userSetting.getUseCustomSsrcForParentInvite() || gb28181Sdp.getSsrc() == null) { | |
| 373 | 366 | // 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式 |
| 374 | 367 | ssrc = "Play".equalsIgnoreCase(sessionName) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) : ssrcFactory.getPlayBackSsrc(mediaServerItem.getId()); |
| 375 | - } else { | |
| 376 | - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); | |
| 368 | + }else { | |
| 369 | + ssrc = gb28181Sdp.getSsrc(); | |
| 377 | 370 | } |
| 378 | 371 | String streamTypeStr = null; |
| 379 | 372 | if (mediaTransmissionTCP) { |
| ... | ... | @@ -406,8 +399,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 406 | 399 | |
| 407 | 400 | Long finalStartTime = startTime; |
| 408 | 401 | Long finalStopTime = stopTime; |
| 409 | - InviteErrorCallback<Object> hookEvent = (code, msg, data) -> { | |
| 410 | - StreamInfo streamInfo = (StreamInfo) data; | |
| 402 | + ErrorCallback<Object> hookEvent = (code, msg, data) -> { | |
| 403 | + StreamInfo streamInfo = (StreamInfo)data; | |
| 411 | 404 | MediaServerItem mediaServerItemInUSe = mediaServerService.getOne(streamInfo.getMediaServerId()); |
| 412 | 405 | logger.info("[上级Invite]下级已经开始推流。 回复200OK(SDP), {}/{}", streamInfo.getApp(), streamInfo.getStream()); |
| 413 | 406 | // * 0 等待设备推流上来 |
| ... | ... | @@ -460,7 +453,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 460 | 453 | logger.error("[命令发送失败] 国标级联 回复SdpAck", e); |
| 461 | 454 | } |
| 462 | 455 | }; |
| 463 | - InviteErrorCallback<Object> errorEvent = ((statusCode, msg, data) -> { | |
| 456 | + ErrorCallback<Object> errorEvent = ((statusCode, msg, data) -> { | |
| 464 | 457 | // 未知错误。直接转发设备点播的错误 |
| 465 | 458 | try { |
| 466 | 459 | if (statusCode > 0) { |
| ... | ... | @@ -547,11 +540,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 547 | 540 | } else if (gbStream != null) { |
| 548 | 541 | |
| 549 | 542 | String ssrc; |
| 550 | - if (userSetting.getUseCustomSsrcForParentInvite() || ssrcIndex < 0) { | |
| 543 | + if (userSetting.getUseCustomSsrcForParentInvite() || gb28181Sdp.getSsrc() == null) { | |
| 551 | 544 | // 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式 |
| 552 | 545 | ssrc = "Play".equalsIgnoreCase(sessionName) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) : ssrcFactory.getPlayBackSsrc(mediaServerItem.getId()); |
| 553 | - } else { | |
| 554 | - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12); | |
| 546 | + }else { | |
| 547 | + ssrc = gb28181Sdp.getSsrc(); | |
| 555 | 548 | } |
| 556 | 549 | |
| 557 | 550 | if ("push".equals(gbStream.getStreamType())) { |
| ... | ... | @@ -690,10 +683,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 690 | 683 | logger.info("[ app={}, stream={} ]通道未推流,启用流后开始推流", gbStream.getApp(), gbStream.getStream()); |
| 691 | 684 | // 监听流上线 |
| 692 | 685 | HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(gbStream.getApp(), gbStream.getStream(), true, "rtsp", mediaServerItem.getId()); |
| 693 | - zlmHttpHookSubscribe.addSubscribe(hookSubscribe, (mediaServerItemInUSe, responseJSON) -> { | |
| 694 | - String app = responseJSON.getString("app"); | |
| 695 | - String stream = responseJSON.getString("stream"); | |
| 696 | - logger.info("[上级点播]拉流代理已经就绪, {}/{}", app, stream); | |
| 686 | + zlmHttpHookSubscribe.addSubscribe(hookSubscribe, (mediaServerItemInUSe, hookParam) -> { | |
| 687 | + OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam)hookParam; | |
| 688 | + logger.info("[上级点播]拉流代理已经就绪, {}/{}", streamChangedHookParam.getApp(), streamChangedHookParam.getStream()); | |
| 697 | 689 | dynamicTask.stop(callIdHeader.getCallId()); |
| 698 | 690 | pushProxyStream(evt, request, gbStream, platform, callIdHeader, mediaServerItem, port, tcpActive, |
| 699 | 691 | mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId); |
| ... | ... | @@ -971,20 +963,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 971 | 963 | } |
| 972 | 964 | String contentString = new String(request.getRawContent()); |
| 973 | 965 | // jainSip不支持y=字段, 移除移除以解析。 |
| 974 | - String substring = contentString; | |
| 975 | 966 | String ssrc = "0000000404"; |
| 976 | - int ssrcIndex = contentString.indexOf("y="); | |
| 977 | - if (ssrcIndex > 0) { | |
| 978 | - substring = contentString.substring(0, ssrcIndex); | |
| 979 | - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12).trim(); | |
| 980 | - } | |
| 981 | - ssrcIndex = substring.indexOf("f="); | |
| 982 | - if (ssrcIndex > 0) { | |
| 983 | - substring = contentString.substring(0, ssrcIndex); | |
| 984 | - } | |
| 985 | - try { | |
| 986 | - SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); | |
| 987 | 967 | |
| 968 | + try { | |
| 969 | + Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString); | |
| 970 | + SessionDescription sdp = gb28181Sdp.getBaseSdb(); | |
| 988 | 971 | // 获取支持的格式 |
| 989 | 972 | Vector mediaDescriptions = sdp.getMediaDescriptions(true); |
| 990 | 973 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; |
| 2 | 2 | |
| 3 | +import com.genersoft.iot.vmp.conf.CivilCodeFileConf; | |
| 3 | 4 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 4 | 5 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 5 | 6 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| ... | ... | @@ -20,7 +21,10 @@ import org.springframework.stereotype.Component; |
| 20 | 21 | |
| 21 | 22 | import javax.sip.RequestEvent; |
| 22 | 23 | import javax.sip.header.FromHeader; |
| 23 | -import java.util.*; | |
| 24 | +import java.util.ArrayList; | |
| 25 | +import java.util.Iterator; | |
| 26 | +import java.util.List; | |
| 27 | +import java.util.Map; | |
| 24 | 28 | import java.util.concurrent.ConcurrentHashMap; |
| 25 | 29 | import java.util.concurrent.CopyOnWriteArrayList; |
| 26 | 30 | |
| ... | ... | @@ -56,6 +60,9 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent |
| 56 | 60 | @Autowired |
| 57 | 61 | private DynamicTask dynamicTask; |
| 58 | 62 | |
| 63 | + @Autowired | |
| 64 | + private CivilCodeFileConf civilCodeFileConf; | |
| 65 | + | |
| 59 | 66 | private final static String talkKey = "notify-request-for-catalog-task"; |
| 60 | 67 | |
| 61 | 68 | public void process(RequestEvent evt) { |
| ... | ... | @@ -65,7 +72,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent |
| 65 | 72 | String deviceId = SipUtils.getUserIdFromFromHeader(fromHeader); |
| 66 | 73 | |
| 67 | 74 | Device device = redisCatchStorage.getDevice(deviceId); |
| 68 | - if (device == null || device.getOnline() == 0) { | |
| 75 | + if (device == null || !device.isOnLine()) { | |
| 69 | 76 | logger.warn("[收到目录订阅]:{}, 但是设备已经离线", (device != null ? device.getDeviceId():"" )); |
| 70 | 77 | return; |
| 71 | 78 | } |
| ... | ... | @@ -96,7 +103,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent |
| 96 | 103 | }else { |
| 97 | 104 | event = eventElement.getText().toUpperCase(); |
| 98 | 105 | } |
| 99 | - DeviceChannel channel = XmlUtil.channelContentHander(itemDevice, device, event); | |
| 106 | + DeviceChannel channel = XmlUtil.channelContentHandler(itemDevice, device, event, civilCodeFileConf); | |
| 100 | 107 | |
| 101 | 108 | channel.setDeviceId(device.getDeviceId()); |
| 102 | 109 | logger.info("[收到目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId()); |
| ... | ... | @@ -175,6 +182,11 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent |
| 175 | 182 | } |
| 176 | 183 | }else { |
| 177 | 184 | addChannelMap.put(channel.getChannelId(), channel); |
| 185 | + if (userSetting.getDeviceStatusNotify()) { | |
| 186 | + // 发送redis消息 | |
| 187 | + redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), true); | |
| 188 | + } | |
| 189 | + | |
| 178 | 190 | if (addChannelMap.keySet().size() > 300) { |
| 179 | 191 | executeSaveForAdd(); |
| 180 | 192 | } |
| ... | ... | @@ -185,6 +197,10 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent |
| 185 | 197 | // 删除 |
| 186 | 198 | logger.info("[收到删除通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); |
| 187 | 199 | deleteChannelList.add(channel); |
| 200 | + if (userSetting.getDeviceStatusNotify()) { | |
| 201 | + // 发送redis消息 | |
| 202 | + redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), false); | |
| 203 | + } | |
| 188 | 204 | if (deleteChannelList.size() > 300) { |
| 189 | 205 | executeSaveForDelete(); |
| 190 | 206 | } |
| ... | ... | @@ -205,6 +221,10 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent |
| 205 | 221 | if (addChannelMap.keySet().size() > 300) { |
| 206 | 222 | executeSaveForAdd(); |
| 207 | 223 | } |
| 224 | + if (userSetting.getDeviceStatusNotify()) { | |
| 225 | + // 发送redis消息 | |
| 226 | + redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), true); | |
| 227 | + } | |
| 208 | 228 | } |
| 209 | 229 | break; |
| 210 | 230 | default: |
| ... | ... | @@ -232,7 +252,6 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent |
| 232 | 252 | } |
| 233 | 253 | |
| 234 | 254 | private void executeSave(){ |
| 235 | - System.out.println("定时存储数据"); | |
| 236 | 255 | executeSaveForUpdate(); |
| 237 | 256 | executeSaveForDelete(); |
| 238 | 257 | executeSaveForOnline(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; |
| 2 | 2 | |
| 3 | 3 | import com.alibaba.fastjson2.JSONObject; |
| 4 | +import com.genersoft.iot.vmp.conf.CivilCodeFileConf; | |
| 4 | 5 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 5 | 6 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 6 | 7 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| ... | ... | @@ -79,6 +80,9 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 79 | 80 | @Autowired |
| 80 | 81 | private NotifyRequestForCatalogProcessor notifyRequestForCatalogProcessor; |
| 81 | 82 | |
| 83 | + @Autowired | |
| 84 | + private CivilCodeFileConf civilCodeFileConf; | |
| 85 | + | |
| 82 | 86 | private ConcurrentLinkedQueue<HandlerCatchData> taskQueue = new ConcurrentLinkedQueue<>(); |
| 83 | 87 | |
| 84 | 88 | @Qualifier("taskExecutor") |
| ... | ... | @@ -192,7 +196,12 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 192 | 196 | mobilePosition.setDeviceId(device.getDeviceId()); |
| 193 | 197 | mobilePosition.setChannelId(channelId); |
| 194 | 198 | String time = XmlUtil.getText(rootElement, "Time"); |
| 195 | - mobilePosition.setTime(time); | |
| 199 | + if (ObjectUtils.isEmpty(time)){ | |
| 200 | + mobilePosition.setTime(DateUtil.getNow()); | |
| 201 | + }else { | |
| 202 | + mobilePosition.setTime(SipUtils.parseTime(time)); | |
| 203 | + } | |
| 204 | + | |
| 196 | 205 | mobilePosition.setLongitude(Double.parseDouble(XmlUtil.getText(rootElement, "Longitude"))); |
| 197 | 206 | mobilePosition.setLatitude(Double.parseDouble(XmlUtil.getText(rootElement, "Latitude"))); |
| 198 | 207 | if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Speed"))) { |
| ... | ... | @@ -237,7 +246,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 237 | 246 | |
| 238 | 247 | // 发送redis消息。 通知位置信息的变化 |
| 239 | 248 | JSONObject jsonObject = new JSONObject(); |
| 240 | - jsonObject.put("time", time); | |
| 249 | + jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); | |
| 241 | 250 | jsonObject.put("serial", deviceId); |
| 242 | 251 | jsonObject.put("code", channelId); |
| 243 | 252 | jsonObject.put("longitude", mobilePosition.getLongitude()); |
| ... | ... | @@ -339,7 +348,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 339 | 348 | storager.updateChannelPosition(deviceChannel); |
| 340 | 349 | // 发送redis消息。 通知位置信息的变化 |
| 341 | 350 | JSONObject jsonObject = new JSONObject(); |
| 342 | - jsonObject.put("time", mobilePosition.getTime()); | |
| 351 | + jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); | |
| 343 | 352 | jsonObject.put("serial", deviceChannel.getDeviceId()); |
| 344 | 353 | jsonObject.put("code", deviceChannel.getChannelId()); |
| 345 | 354 | jsonObject.put("longitude", mobilePosition.getLongitude()); |
| ... | ... | @@ -372,7 +381,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 372 | 381 | String deviceId = SipUtils.getUserIdFromFromHeader(fromHeader); |
| 373 | 382 | |
| 374 | 383 | Device device = redisCatchStorage.getDevice(deviceId); |
| 375 | - if (device == null || device.getOnline() == 0) { | |
| 384 | + if (device == null || !device.isOnLine()) { | |
| 376 | 385 | logger.warn("[收到目录订阅]:{}, 但是设备已经离线", (device != null ? device.getDeviceId():"" )); |
| 377 | 386 | return; |
| 378 | 387 | } |
| ... | ... | @@ -403,7 +412,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 403 | 412 | }else { |
| 404 | 413 | event = eventElement.getText().toUpperCase(); |
| 405 | 414 | } |
| 406 | - DeviceChannel channel = XmlUtil.channelContentHander(itemDevice, device, event); | |
| 415 | + DeviceChannel channel = XmlUtil.channelContentHandler(itemDevice, device, event, civilCodeFileConf); | |
| 407 | 416 | channel.setDeviceId(device.getDeviceId()); |
| 408 | 417 | logger.info("[收到目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId()); |
| 409 | 418 | switch (event) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
| ... | ... | @@ -167,9 +167,8 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen |
| 167 | 167 | device.setStreamMode("UDP"); |
| 168 | 168 | device.setCharset("GB2312"); |
| 169 | 169 | device.setGeoCoordSys("WGS84"); |
| 170 | - device.setTreeType("CivilCode"); | |
| 171 | 170 | device.setDeviceId(deviceId); |
| 172 | - device.setOnline(0); | |
| 171 | + device.setOnLine(false); | |
| 173 | 172 | } |
| 174 | 173 | device.setIp(remoteAddressInfo.getIp()); |
| 175 | 174 | device.setPort(remoteAddressInfo.getPort()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java
| ... | ... | @@ -164,7 +164,7 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme |
| 164 | 164 | |
| 165 | 165 | // 发送redis消息。 通知位置信息的变化 |
| 166 | 166 | JSONObject jsonObject = new JSONObject(); |
| 167 | - jsonObject.put("time", mobilePosition.getTime()); | |
| 167 | + jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); | |
| 168 | 168 | jsonObject.put("serial", deviceChannel.getDeviceId()); |
| 169 | 169 | jsonObject.put("code", deviceChannel.getChannelId()); |
| 170 | 170 | jsonObject.put("longitude", mobilePosition.getLongitude()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
| ... | ... | @@ -83,12 +83,12 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp |
| 83 | 83 | |
| 84 | 84 | device.setKeepaliveTime(DateUtil.getNow()); |
| 85 | 85 | |
| 86 | - if (device.getOnline() == 1) { | |
| 86 | + if (device.isOnLine()) { | |
| 87 | 87 | deviceService.updateDevice(device); |
| 88 | 88 | }else { |
| 89 | 89 | // 对于已经离线的设备判断他的注册是否已经过期 |
| 90 | 90 | if (!deviceService.expire(device)){ |
| 91 | - device.setOnline(0); | |
| 91 | + device.setOnLine(false); | |
| 92 | 92 | deviceService.online(device, null); |
| 93 | 93 | } |
| 94 | 94 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java
| ... | ... | @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP |
| 7 | 7 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; |
| 8 | 8 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; |
| 9 | 9 | import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; |
| 10 | +import com.genersoft.iot.vmp.gb28181.utils.SipUtils; | |
| 10 | 11 | import com.genersoft.iot.vmp.service.IDeviceChannelService; |
| 11 | 12 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 12 | 13 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| ... | ... | @@ -95,7 +96,12 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen |
| 95 | 96 | } |
| 96 | 97 | mobilePosition.setDeviceId(sipMsgInfo.getDevice().getDeviceId()); |
| 97 | 98 | mobilePosition.setChannelId(getText(rootElementAfterCharset, "DeviceID")); |
| 98 | - mobilePosition.setTime(getText(rootElementAfterCharset, "Time")); | |
| 99 | + String time = getText(rootElementAfterCharset, "Time"); | |
| 100 | + if (ObjectUtils.isEmpty(time)){ | |
| 101 | + mobilePosition.setTime(DateUtil.getNow()); | |
| 102 | + }else { | |
| 103 | + mobilePosition.setTime(SipUtils.parseTime(time)); | |
| 104 | + } | |
| 99 | 105 | mobilePosition.setLongitude(Double.parseDouble(getText(rootElementAfterCharset, "Longitude"))); |
| 100 | 106 | mobilePosition.setLatitude(Double.parseDouble(getText(rootElementAfterCharset, "Latitude"))); |
| 101 | 107 | if (NumericUtil.isDouble(getText(rootElementAfterCharset, "Speed"))) { |
| ... | ... | @@ -138,7 +144,7 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen |
| 138 | 144 | |
| 139 | 145 | // 发送redis消息。 通知位置信息的变化 |
| 140 | 146 | JSONObject jsonObject = new JSONObject(); |
| 141 | - jsonObject.put("time", mobilePosition.getTime()); | |
| 147 | + jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); | |
| 142 | 148 | jsonObject.put("serial", deviceChannel.getDeviceId()); |
| 143 | 149 | jsonObject.put("code", deviceChannel.getChannelId()); |
| 144 | 150 | jsonObject.put("longitude", mobilePosition.getLongitude()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java
| ... | ... | @@ -77,7 +77,7 @@ public class DeviceStatusQueryMessageHandler extends SIPRequestProcessorParent i |
| 77 | 77 | return; |
| 78 | 78 | } |
| 79 | 79 | try { |
| 80 | - cmderFroPlatform.deviceStatusResponse(parentPlatform,channelId, sn, fromHeader.getTag(),deviceChannel.getStatus()); | |
| 80 | + cmderFroPlatform.deviceStatusResponse(parentPlatform,channelId, sn, fromHeader.getTag(),deviceChannel.isStatus()); | |
| 81 | 81 | } catch (SipException | InvalidArgumentException | ParseException e) { |
| 82 | 82 | logger.error("[命令发送失败] 国标级联 DeviceStatus查询回复: {}", e.getMessage()); |
| 83 | 83 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; |
| 2 | 2 | |
| 3 | +import com.genersoft.iot.vmp.conf.CivilCodeFileConf; | |
| 3 | 4 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| 4 | 5 | import com.genersoft.iot.vmp.gb28181.session.CatalogDataCatch; |
| 5 | 6 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; |
| ... | ... | @@ -54,6 +55,9 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp |
| 54 | 55 | @Autowired |
| 55 | 56 | private ThreadPoolTaskExecutor taskExecutor; |
| 56 | 57 | |
| 58 | + @Autowired | |
| 59 | + private CivilCodeFileConf civilCodeFileConf; | |
| 60 | + | |
| 57 | 61 | @Override |
| 58 | 62 | public void afterPropertiesSet() throws Exception { |
| 59 | 63 | responseMessageHandler.addHandler(cmdType, this); |
| ... | ... | @@ -101,6 +105,7 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp |
| 101 | 105 | Iterator<Element> deviceListIterator = deviceListElement.elementIterator(); |
| 102 | 106 | if (deviceListIterator != null) { |
| 103 | 107 | List<DeviceChannel> channelList = new ArrayList<>(); |
| 108 | + List<String> parentChannelIds = new ArrayList<>(); | |
| 104 | 109 | // 遍历DeviceList |
| 105 | 110 | while (deviceListIterator.hasNext()) { |
| 106 | 111 | Element itemDevice = deviceListIterator.next(); |
| ... | ... | @@ -108,7 +113,7 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp |
| 108 | 113 | if (channelDeviceElement == null) { |
| 109 | 114 | continue; |
| 110 | 115 | } |
| 111 | - DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice, device, null); | |
| 116 | + DeviceChannel deviceChannel = XmlUtil.channelContentHandler(itemDevice, device, null, civilCodeFileConf); | |
| 112 | 117 | deviceChannel = SipUtils.updateGps(deviceChannel, device.getGeoCoordSys()); |
| 113 | 118 | deviceChannel.setDeviceId(take.getDevice().getDeviceId()); |
| 114 | 119 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; |
| 2 | 2 | |
| 3 | -import com.genersoft.iot.vmp.common.VideoManagerConstants; | |
| 4 | -import com.genersoft.iot.vmp.conf.SipConfig; | |
| 5 | 3 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 6 | 4 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 7 | -import com.genersoft.iot.vmp.gb28181.event.EventPublisher; | |
| 8 | 5 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 9 | 6 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 10 | 7 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; |
| 11 | 8 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; |
| 12 | 9 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; |
| 13 | 10 | import com.genersoft.iot.vmp.service.IDeviceService; |
| 14 | -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 15 | -import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | |
| 16 | 11 | import gov.nist.javax.sip.message.SIPRequest; |
| 17 | 12 | import org.dom4j.DocumentException; |
| 18 | 13 | import org.dom4j.Element; |
| ... | ... | @@ -59,7 +54,7 @@ public class DeviceInfoResponseMessageHandler extends SIPRequestProcessorParent |
| 59 | 54 | public void handForDevice(RequestEvent evt, Device device, Element rootElement) { |
| 60 | 55 | logger.debug("接收到DeviceInfo应答消息"); |
| 61 | 56 | // 检查设备是否存在, 不存在则不回复 |
| 62 | - if (device == null || device.getOnline() == 0) { | |
| 57 | + if (device == null || !device.isOnLine()) { | |
| 63 | 58 | logger.warn("[接收到DeviceInfo应答消息,但是设备已经离线]:" + (device != null ? device.getDeviceId():"" )); |
| 64 | 59 | return; |
| 65 | 60 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java
| ... | ... | @@ -2,17 +2,21 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.respon |
| 2 | 2 | |
| 3 | 3 | import com.alibaba.fastjson2.JSONObject; |
| 4 | 4 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 5 | -import com.genersoft.iot.vmp.gb28181.bean.*; | |
| 5 | +import com.genersoft.iot.vmp.gb28181.bean.Device; | |
| 6 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | |
| 7 | +import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; | |
| 8 | +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | |
| 9 | +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | |
| 10 | +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; | |
| 6 | 11 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; |
| 7 | 12 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; |
| 8 | 13 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; |
| 9 | -import com.genersoft.iot.vmp.gb28181.utils.Coordtransform; | |
| 10 | 14 | import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; |
| 15 | +import com.genersoft.iot.vmp.gb28181.utils.SipUtils; | |
| 11 | 16 | import com.genersoft.iot.vmp.service.IDeviceChannelService; |
| 12 | 17 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 13 | 18 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 14 | 19 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 15 | -import com.genersoft.iot.vmp.utils.GpsUtil; | |
| 16 | 20 | import gov.nist.javax.sip.message.SIPRequest; |
| 17 | 21 | import org.dom4j.DocumentException; |
| 18 | 22 | import org.dom4j.Element; |
| ... | ... | @@ -56,6 +60,9 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar |
| 56 | 60 | @Autowired |
| 57 | 61 | private IDeviceChannelService deviceChannelService; |
| 58 | 62 | |
| 63 | + @Autowired | |
| 64 | + private DeferredResultHolder resultHolder; | |
| 65 | + | |
| 59 | 66 | @Override |
| 60 | 67 | public void afterPropertiesSet() throws Exception { |
| 61 | 68 | responseMessageHandler.addHandler(cmdType, this); |
| ... | ... | @@ -83,7 +90,13 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar |
| 83 | 90 | } |
| 84 | 91 | mobilePosition.setDeviceId(device.getDeviceId()); |
| 85 | 92 | mobilePosition.setChannelId(getText(rootElement, "DeviceID")); |
| 86 | - mobilePosition.setTime(getText(rootElement, "Time")); | |
| 93 | + //兼容ISO 8601格式时间 | |
| 94 | + String time = getText(rootElement, "Time"); | |
| 95 | + if (ObjectUtils.isEmpty(time)){ | |
| 96 | + mobilePosition.setTime(DateUtil.getNow()); | |
| 97 | + }else { | |
| 98 | + mobilePosition.setTime(SipUtils.parseTime(time)); | |
| 99 | + } | |
| 87 | 100 | mobilePosition.setLongitude(Double.parseDouble(getText(rootElement, "Longitude"))); |
| 88 | 101 | mobilePosition.setLatitude(Double.parseDouble(getText(rootElement, "Latitude"))); |
| 89 | 102 | if (NumericUtil.isDouble(getText(rootElement, "Speed"))) { |
| ... | ... | @@ -121,11 +134,18 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar |
| 121 | 134 | if (userSetting.getSavePositionHistory()) { |
| 122 | 135 | storager.insertMobilePosition(mobilePosition); |
| 123 | 136 | } |
| 137 | + | |
| 124 | 138 | storager.updateChannelPosition(deviceChannel); |
| 125 | 139 | |
| 140 | + String key = DeferredResultHolder.CALLBACK_CMD_MOBILE_POSITION + device.getDeviceId(); | |
| 141 | + RequestMessage msg = new RequestMessage(); | |
| 142 | + msg.setKey(key); | |
| 143 | + msg.setData(mobilePosition); | |
| 144 | + resultHolder.invokeAllResult(msg); | |
| 145 | + | |
| 126 | 146 | // 发送redis消息。 通知位置信息的变化 |
| 127 | 147 | JSONObject jsonObject = new JSONObject(); |
| 128 | - jsonObject.put("time", mobilePosition.getTime()); | |
| 148 | + jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime())); | |
| 129 | 149 | jsonObject.put("serial", deviceChannel.getDeviceId()); |
| 130 | 150 | jsonObject.put("code", deviceChannel.getChannelId()); |
| 131 | 151 | jsonObject.put("longitude", mobilePosition.getLongitude()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.gb28181.SipLayer; |
| 4 | +import com.genersoft.iot.vmp.gb28181.bean.Gb28181Sdp; | |
| 4 | 5 | import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; |
| 5 | 6 | import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; |
| 6 | 7 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; |
| 7 | 8 | import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract; |
| 9 | +import com.genersoft.iot.vmp.gb28181.utils.SipUtils; | |
| 8 | 10 | import gov.nist.javax.sip.ResponseEventExt; |
| 9 | 11 | import gov.nist.javax.sip.message.SIPResponse; |
| 10 | 12 | import org.slf4j.Logger; |
| ... | ... | @@ -12,7 +14,6 @@ import org.slf4j.LoggerFactory; |
| 12 | 14 | import org.springframework.beans.factory.annotation.Autowired; |
| 13 | 15 | import org.springframework.stereotype.Component; |
| 14 | 16 | |
| 15 | -import javax.sdp.SdpFactory; | |
| 16 | 17 | import javax.sdp.SdpParseException; |
| 17 | 18 | import javax.sdp.SessionDescription; |
| 18 | 19 | import javax.sip.InvalidArgumentException; |
| ... | ... | @@ -82,19 +83,8 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract { |
| 82 | 83 | ResponseEventExt event = (ResponseEventExt)evt; |
| 83 | 84 | |
| 84 | 85 | String contentString = new String(response.getRawContent()); |
| 85 | - // jainSip不支持y=字段, 移除以解析。 | |
| 86 | - int ssrcIndex = contentString.indexOf("y="); | |
| 87 | - // 检查是否有y字段 | |
| 88 | - SessionDescription sdp; | |
| 89 | - if (ssrcIndex >= 0) { | |
| 90 | - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 | |
| 91 | - String substring = contentString.substring(0, contentString.indexOf("y=")); | |
| 92 | - sdp = SdpFactory.getInstance().createSessionDescription(substring); | |
| 93 | - } else { | |
| 94 | - sdp = SdpFactory.getInstance().createSessionDescription(contentString); | |
| 95 | - } | |
| 96 | - // 查看是否是来自设备的,此是回复 | |
| 97 | - | |
| 86 | + Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString); | |
| 87 | + SessionDescription sdp = gb28181Sdp.getBaseSdb(); | |
| 98 | 88 | SipURI requestUri = SipFactory.getInstance().createAddressFactory().createSipURI(sdp.getOrigin().getUsername(), event.getRemoteIpAddress() + ":" + event.getRemotePort()); |
| 99 | 89 | Request reqAck = headerProvider.createAckRequest(response.getLocalAddress().getHostAddress(), requestUri, response); |
| 100 | 90 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java
| ... | ... | @@ -102,7 +102,7 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract { |
| 102 | 102 | SipTransactionInfo sipTransactionInfo = new SipTransactionInfo(response); |
| 103 | 103 | platformService.online(parentPlatform, sipTransactionInfo); |
| 104 | 104 | }else { |
| 105 | - platformService.offline(parentPlatform, false); | |
| 105 | + platformService.offline(parentPlatform, true); | |
| 106 | 106 | } |
| 107 | 107 | |
| 108 | 108 | // 注册/注销成功移除缓存的信息 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181.utils; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 4 | +import com.genersoft.iot.vmp.gb28181.bean.Gb28181Sdp; | |
| 4 | 5 | import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo; |
| 6 | +import com.genersoft.iot.vmp.utils.DateUtil; | |
| 5 | 7 | import com.genersoft.iot.vmp.utils.GitUtil; |
| 6 | 8 | import gov.nist.javax.sip.address.AddressImpl; |
| 7 | 9 | import gov.nist.javax.sip.address.SipUri; |
| 8 | 10 | import gov.nist.javax.sip.header.Subject; |
| 9 | 11 | import gov.nist.javax.sip.message.SIPRequest; |
| 12 | +import org.apache.commons.lang3.RandomStringUtils; | |
| 13 | +import org.slf4j.Logger; | |
| 14 | +import org.slf4j.LoggerFactory; | |
| 10 | 15 | import org.springframework.util.ObjectUtils; |
| 11 | 16 | |
| 17 | +import javax.sdp.SdpFactory; | |
| 18 | +import javax.sdp.SdpParseException; | |
| 19 | +import javax.sdp.SessionDescription; | |
| 12 | 20 | import javax.sip.PeerUnavailableException; |
| 13 | 21 | import javax.sip.SipFactory; |
| 14 | 22 | import javax.sip.header.FromHeader; |
| ... | ... | @@ -16,6 +24,8 @@ import javax.sip.header.Header; |
| 16 | 24 | import javax.sip.header.UserAgentHeader; |
| 17 | 25 | import javax.sip.message.Request; |
| 18 | 26 | import java.text.ParseException; |
| 27 | +import java.time.LocalDateTime; | |
| 28 | +import java.time.format.DateTimeParseException; | |
| 19 | 29 | import java.util.ArrayList; |
| 20 | 30 | import java.util.List; |
| 21 | 31 | import java.util.UUID; |
| ... | ... | @@ -28,6 +38,8 @@ import java.util.UUID; |
| 28 | 38 | */ |
| 29 | 39 | public class SipUtils { |
| 30 | 40 | |
| 41 | + private final static Logger logger = LoggerFactory.getLogger(SipUtils.class); | |
| 42 | + | |
| 31 | 43 | public static String getUserIdFromFromHeader(Request request) { |
| 32 | 44 | FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); |
| 33 | 45 | return getUserIdFromFromHeader(fromHeader); |
| ... | ... | @@ -51,7 +63,7 @@ public class SipUtils { |
| 51 | 63 | } |
| 52 | 64 | |
| 53 | 65 | public static String getNewViaTag() { |
| 54 | - return "z9hG4bK" + System.currentTimeMillis(); | |
| 66 | + return "z9hG4bK" + RandomStringUtils.randomNumeric(10); | |
| 55 | 67 | } |
| 56 | 68 | |
| 57 | 69 | public static UserAgentHeader createUserAgentHeader(GitUtil gitUtil) throws PeerUnavailableException, ParseException { |
| ... | ... | @@ -113,6 +125,12 @@ public class SipUtils { |
| 113 | 125 | strTmp = String.format("%02X", moveSpeed); |
| 114 | 126 | builder.append(strTmp, 0, 2); |
| 115 | 127 | builder.append(strTmp, 0, 2); |
| 128 | + | |
| 129 | + //优化zoom低倍速下的变倍速率 | |
| 130 | + if ((zoomSpeed > 0) && (zoomSpeed <16)) | |
| 131 | + { | |
| 132 | + zoomSpeed = 16; | |
| 133 | + } | |
| 116 | 134 | strTmp = String.format("%X", zoomSpeed); |
| 117 | 135 | builder.append(strTmp, 0, 1).append("0"); |
| 118 | 136 | //计算校验码 |
| ... | ... | @@ -203,4 +221,66 @@ public class SipUtils { |
| 203 | 221 | } |
| 204 | 222 | return deviceChannel; |
| 205 | 223 | } |
| 224 | + | |
| 225 | + public static Gb28181Sdp parseSDP(String sdpStr) throws SdpParseException { | |
| 226 | + | |
| 227 | + // jainSip不支持y= f=字段, 移除以解析。 | |
| 228 | + int ssrcIndex = sdpStr.indexOf("y="); | |
| 229 | + int mediaDescriptionIndex = sdpStr.indexOf("f="); | |
| 230 | + // 检查是否有y字段 | |
| 231 | + SessionDescription sdp; | |
| 232 | + String ssrc = null; | |
| 233 | + String mediaDescription = null; | |
| 234 | + if (mediaDescriptionIndex == 0 && ssrcIndex == 0) { | |
| 235 | + sdp = SdpFactory.getInstance().createSessionDescription(sdpStr); | |
| 236 | + }else { | |
| 237 | + String lines[] = sdpStr.split("\\r?\\n"); | |
| 238 | + StringBuilder sdpBuffer = new StringBuilder(); | |
| 239 | + for (String line : lines) { | |
| 240 | + if (line.trim().startsWith("y=")) { | |
| 241 | + ssrc = line.substring(2); | |
| 242 | + }else if (line.trim().startsWith("f=")) { | |
| 243 | + mediaDescription = line.substring(2); | |
| 244 | + }else { | |
| 245 | + sdpBuffer.append(line.trim()).append("\r\n"); | |
| 246 | + } | |
| 247 | + } | |
| 248 | + sdp = SdpFactory.getInstance().createSessionDescription(sdpBuffer.toString()); | |
| 249 | + } | |
| 250 | + return Gb28181Sdp.getInstance(sdp, ssrc, mediaDescription); | |
| 251 | + } | |
| 252 | + | |
| 253 | + public static String getSsrcFromSdp(String sdpStr) { | |
| 254 | + | |
| 255 | + // jainSip不支持y= f=字段, 移除以解析。 | |
| 256 | + int ssrcIndex = sdpStr.indexOf("y="); | |
| 257 | + if (ssrcIndex == 0) { | |
| 258 | + return null; | |
| 259 | + } | |
| 260 | + String lines[] = sdpStr.split("\\r?\\n"); | |
| 261 | + for (String line : lines) { | |
| 262 | + if (line.trim().startsWith("y=")) { | |
| 263 | + return line.substring(2); | |
| 264 | + } | |
| 265 | + } | |
| 266 | + return null; | |
| 267 | + } | |
| 268 | + | |
| 269 | + public static String parseTime(String timeStr) { | |
| 270 | + if (ObjectUtils.isEmpty(timeStr)){ | |
| 271 | + return null; | |
| 272 | + } | |
| 273 | + LocalDateTime localDateTime; | |
| 274 | + try { | |
| 275 | + localDateTime = LocalDateTime.parse(timeStr); | |
| 276 | + }catch (DateTimeParseException e) { | |
| 277 | + try { | |
| 278 | + localDateTime = LocalDateTime.parse(timeStr, DateUtil.formatterISO8601); | |
| 279 | + }catch (DateTimeParseException e2) { | |
| 280 | + logger.error("[格式化时间] 无法格式化时间: {}", timeStr); | |
| 281 | + return null; | |
| 282 | + } | |
| 283 | + } | |
| 284 | + return localDateTime.format(DateUtil.formatterISO8601); | |
| 285 | + } | |
| 206 | 286 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
| ... | ... | @@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.gb28181.utils; |
| 2 | 2 | |
| 3 | 3 | import com.alibaba.fastjson2.JSONArray; |
| 4 | 4 | import com.alibaba.fastjson2.JSONObject; |
| 5 | +import com.genersoft.iot.vmp.common.CivilCodePo; | |
| 6 | +import com.genersoft.iot.vmp.conf.CivilCodeFileConf; | |
| 5 | 7 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 6 | 8 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 7 | 9 | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
| ... | ... | @@ -192,7 +194,7 @@ public class XmlUtil { |
| 192 | 194 | CivilCode, BusinessGroup,VirtualOrganization,Other |
| 193 | 195 | } |
| 194 | 196 | |
| 195 | - public static DeviceChannel channelContentHander(Element itemDevice, Device device, String event){ | |
| 197 | + public static DeviceChannel channelContentHandler(Element itemDevice, Device device, String event, CivilCodeFileConf civilCodeFileConf){ | |
| 196 | 198 | DeviceChannel deviceChannel = new DeviceChannel(); |
| 197 | 199 | deviceChannel.setDeviceId(device.getDeviceId()); |
| 198 | 200 | Element channdelIdElement = itemDevice.element("DeviceID"); |
| ... | ... | @@ -210,208 +212,353 @@ public class XmlUtil { |
| 210 | 212 | // 除了ADD和update情况下需要识别全部内容, |
| 211 | 213 | return deviceChannel; |
| 212 | 214 | } |
| 213 | - | |
| 214 | - ChannelType channelType = ChannelType.Other; | |
| 215 | - if (channelId.length() <= 8) { | |
| 216 | - channelType = ChannelType.CivilCode; | |
| 215 | + Element nameElement = itemDevice.element("Name"); | |
| 216 | + if (nameElement != null) { | |
| 217 | + deviceChannel.setName(nameElement.getText()); | |
| 218 | + } | |
| 219 | + if(channelId.length() <= 8) { | |
| 217 | 220 | deviceChannel.setHasAudio(false); |
| 221 | + CivilCodePo parentCode = civilCodeFileConf.getParentCode(channelId); | |
| 222 | + if (parentCode != null) { | |
| 223 | + deviceChannel.setParentId(parentCode.getCode()); | |
| 224 | + deviceChannel.setCivilCode(parentCode.getCode()); | |
| 225 | + }else { | |
| 226 | + logger.warn("[xml解析] 无法确定行政区划{}的上级行政区划", channelId); | |
| 227 | + } | |
| 228 | + deviceChannel.setStatus(true); | |
| 229 | + return deviceChannel; | |
| 218 | 230 | }else { |
| 219 | - if (channelId.length() == 20) { | |
| 220 | - int code = Integer.parseInt(channelId.substring(10, 13)); | |
| 221 | - switch (code){ | |
| 222 | - case 215: | |
| 223 | - channelType = ChannelType.BusinessGroup; | |
| 224 | - deviceChannel.setHasAudio(false); | |
| 225 | - break; | |
| 226 | - case 216: | |
| 227 | - channelType = ChannelType.VirtualOrganization; | |
| 228 | - deviceChannel.setHasAudio(false); | |
| 229 | - break; | |
| 230 | - case 136: | |
| 231 | - case 137: | |
| 232 | - case 138: | |
| 233 | - deviceChannel.setHasAudio(true); | |
| 234 | - break; | |
| 235 | - default: | |
| 236 | - deviceChannel.setHasAudio(false); | |
| 237 | - break; | |
| 238 | - | |
| 239 | - } | |
| 231 | + if(channelId.length() != 20) { | |
| 232 | + logger.warn("[xml解析] 失败,编号不符合国标28181定义: {}", channelId); | |
| 233 | + return null; | |
| 240 | 234 | } |
| 241 | - } | |
| 242 | 235 | |
| 243 | - Element channdelNameElement = itemDevice.element("Name"); | |
| 244 | - String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim() : ""; | |
| 245 | - deviceChannel.setName(channelName); | |
| 246 | - | |
| 247 | - String civilCode = XmlUtil.getText(itemDevice, "CivilCode"); | |
| 248 | - deviceChannel.setCivilCode(civilCode); | |
| 249 | - if (channelType == ChannelType.CivilCode && civilCode == null) { | |
| 250 | - deviceChannel.setParental(1); | |
| 251 | - // 行政区划如果没有传递具体值,则推测一个 | |
| 252 | - if (channelId.length() > 2) { | |
| 253 | - deviceChannel.setCivilCode(channelId.substring(0, channelId.length() - 2)); | |
| 254 | - } | |
| 255 | - } | |
| 256 | - if (channelType.equals(ChannelType.CivilCode)) { | |
| 257 | - // 行政区划其他字段没必要识别了,默认在线即可 | |
| 258 | - deviceChannel.setStatus(1); | |
| 259 | - deviceChannel.setParental(1); | |
| 260 | - deviceChannel.setCreateTime(DateUtil.getNow()); | |
| 261 | - deviceChannel.setUpdateTime(DateUtil.getNow()); | |
| 262 | - return deviceChannel; | |
| 263 | - } | |
| 264 | - /** | |
| 265 | - * 行政区划展示设备树与业务分组展示设备树是两种不同的模式 | |
| 266 | - * 行政区划展示设备树 各个目录之间主要靠deviceId做关联,摄像头通过CivilCode指定其属于那个行政区划;都是不超过十位的编号; 结构如下: | |
| 267 | - * 河北省 | |
| 268 | - * --> 石家庄市 | |
| 269 | - * --> 摄像头 | |
| 270 | - *String parentId = XmlUtil.getText(itemDevice, "ParentID"); | |
| 271 | - if (parentId != null) { | |
| 272 | - if (parentId.contains("/")) { | |
| 273 | - String lastParentId = parentId.substring(parentId.lastIndexOf("/") + 1); | |
| 274 | - String businessGroup = parentId.substring(0, parentId.indexOf("/")); | |
| 275 | - deviceChannel.setParentId(lastParentId); | |
| 276 | - }else { | |
| 277 | - deviceChannel.setParentId(parentId); | |
| 278 | - } | |
| 279 | - } | |
| 280 | - deviceCh --> 正定县 | |
| 281 | - * --> 摄像头 | |
| 282 | - * --> 摄像头 | |
| 283 | - * | |
| 284 | - * 业务分组展示设备树是顶级是业务分组,其下的虚拟组织靠BusinessGroupID指定其所属的业务分组;摄像头通过ParentId来指定其所属于的虚拟组织: | |
| 285 | - * 业务分组 | |
| 286 | - * --> 虚拟组织 | |
| 287 | - * --> 摄像头 | |
| 288 | - * --> 虚拟组织 | |
| 289 | - * --> 摄像头 | |
| 290 | - * --> 摄像头 | |
| 291 | - */ | |
| 292 | - String parentId = XmlUtil.getText(itemDevice, "ParentID"); | |
| 293 | - String businessGroupID = XmlUtil.getText(itemDevice, "BusinessGroupID"); | |
| 294 | - if (parentId != null) { | |
| 295 | - if (parentId.contains("/")) { | |
| 296 | - String lastParentId = parentId.substring(parentId.lastIndexOf("/") + 1); | |
| 297 | - if (businessGroupID == null) { | |
| 298 | - businessGroupID = parentId.substring(0, parentId.indexOf("/")); | |
| 299 | - } | |
| 300 | - deviceChannel.setParentId(lastParentId); | |
| 236 | + int code = Integer.parseInt(channelId.substring(10, 13)); | |
| 237 | + if (code == 136 || code == 137 || code == 138) { | |
| 238 | + deviceChannel.setHasAudio(true); | |
| 301 | 239 | }else { |
| 302 | - deviceChannel.setParentId(parentId); | |
| 240 | + deviceChannel.setHasAudio(false); | |
| 303 | 241 | } |
| 304 | - // 兼容设备通道信息中自己为自己父节点的情况 | |
| 305 | - if (deviceChannel.getParentId().equals(deviceChannel.getChannelId())) { | |
| 306 | - deviceChannel.setParentId(null); | |
| 242 | + // 设备厂商 | |
| 243 | + String manufacturer = getText(itemDevice, "Manufacturer"); | |
| 244 | + // 设备型号 | |
| 245 | + String model = getText(itemDevice, "Model"); | |
| 246 | + // 设备归属 | |
| 247 | + String owner = getText(itemDevice, "Owner"); | |
| 248 | + // 行政区域 | |
| 249 | + String civilCode = getText(itemDevice, "CivilCode"); | |
| 250 | + // 虚拟组织所属的业务分组ID,业务分组根据特定的业务需求制定,一个业务分组包含一组特定的虚拟组织 | |
| 251 | + String businessGroupID = getText(itemDevice, "BusinessGroupID"); | |
| 252 | + // 父设备/区域/系统ID | |
| 253 | + String parentID = getText(itemDevice, "ParentID"); | |
| 254 | + if (parentID != null && parentID.equalsIgnoreCase("null")) { | |
| 255 | + parentID = null; | |
| 307 | 256 | } |
| 308 | - } | |
| 309 | - deviceChannel.setBusinessGroupId(businessGroupID); | |
| 310 | - if (channelType.equals(ChannelType.BusinessGroup) || channelType.equals(ChannelType.VirtualOrganization)) { | |
| 311 | - // 业务分组和虚拟组织 其他字段没必要识别了,默认在线即可 | |
| 312 | - deviceChannel.setStatus(1); | |
| 313 | - deviceChannel.setParental(1); | |
| 314 | - deviceChannel.setCreateTime(DateUtil.getNow()); | |
| 315 | - deviceChannel.setUpdateTime(DateUtil.getNow()); | |
| 316 | - return deviceChannel; | |
| 317 | - } | |
| 257 | + // 注册方式(必选)缺省为1;1:符合IETFRFC3261标准的认证注册模式;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式 | |
| 258 | + String registerWay = getText(itemDevice, "RegisterWay"); | |
| 259 | + // 保密属性(必选)缺省为0;0:不涉密,1:涉密 | |
| 260 | + String secrecy = getText(itemDevice, "Secrecy"); | |
| 261 | + // 安装地址 | |
| 262 | + String address = getText(itemDevice, "Address"); | |
| 263 | + | |
| 264 | + switch (code){ | |
| 265 | + case 200: | |
| 266 | + // 系统目录 | |
| 267 | + if (!ObjectUtils.isEmpty(manufacturer)) { | |
| 268 | + deviceChannel.setManufacture(manufacturer); | |
| 269 | + } | |
| 270 | + if (!ObjectUtils.isEmpty(model)) { | |
| 271 | + deviceChannel.setModel(model); | |
| 272 | + } | |
| 273 | + if (!ObjectUtils.isEmpty(owner)) { | |
| 274 | + deviceChannel.setOwner(owner); | |
| 275 | + } | |
| 276 | + if (!ObjectUtils.isEmpty(civilCode)) { | |
| 277 | + deviceChannel.setCivilCode(civilCode); | |
| 278 | + deviceChannel.setParentId(civilCode); | |
| 279 | + }else { | |
| 280 | + if (!ObjectUtils.isEmpty(parentID)) { | |
| 281 | + deviceChannel.setParentId(parentID); | |
| 282 | + } | |
| 283 | + } | |
| 284 | + if (!ObjectUtils.isEmpty(address)) { | |
| 285 | + deviceChannel.setAddress(address); | |
| 286 | + } | |
| 287 | + deviceChannel.setStatus(true); | |
| 288 | + if (!ObjectUtils.isEmpty(registerWay)) { | |
| 289 | + try { | |
| 290 | + deviceChannel.setRegisterWay(Integer.parseInt(registerWay)); | |
| 291 | + }catch (NumberFormatException exception) { | |
| 292 | + logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); | |
| 293 | + } | |
| 294 | + } | |
| 295 | + if (!ObjectUtils.isEmpty(secrecy)) { | |
| 296 | + deviceChannel.setSecrecy(secrecy); | |
| 297 | + } | |
| 298 | + return deviceChannel; | |
| 299 | + case 215: | |
| 300 | + // 业务分组 | |
| 301 | + deviceChannel.setStatus(true); | |
| 302 | + if (!ObjectUtils.isEmpty(parentID)) { | |
| 303 | + if (!parentID.trim().equalsIgnoreCase(device.getDeviceId())) { | |
| 304 | + deviceChannel.setParentId(parentID); | |
| 305 | + } | |
| 306 | + }else { | |
| 307 | + logger.warn("[xml解析] 业务分组数据中缺少关键信息->ParentId"); | |
| 308 | + if (!ObjectUtils.isEmpty(civilCode)) { | |
| 309 | + deviceChannel.setCivilCode(civilCode); | |
| 310 | + } | |
| 311 | + } | |
| 312 | + break; | |
| 313 | + case 216: | |
| 314 | + // 虚拟组织 | |
| 315 | + deviceChannel.setStatus(true); | |
| 316 | + if (!ObjectUtils.isEmpty(businessGroupID)) { | |
| 317 | + deviceChannel.setBusinessGroupId(businessGroupID); | |
| 318 | + } | |
| 318 | 319 | |
| 319 | - Element statusElement = itemDevice.element("Status"); | |
| 320 | 320 | |
| 321 | - if (statusElement != null) { | |
| 322 | - String status = statusElement.getTextTrim().trim(); | |
| 323 | - // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 | |
| 324 | - if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) { | |
| 325 | - deviceChannel.setStatus(1); | |
| 326 | - } | |
| 327 | - if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { | |
| 328 | - deviceChannel.setStatus(0); | |
| 329 | - } | |
| 330 | - }else { | |
| 331 | - deviceChannel.setStatus(1); | |
| 332 | - } | |
| 333 | - // 识别自带的目录标识 | |
| 334 | - String parental = XmlUtil.getText(itemDevice, "Parental"); | |
| 335 | - // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1 | |
| 336 | - if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) { | |
| 337 | - deviceChannel.setParental(0); | |
| 338 | - }else { | |
| 339 | - deviceChannel.setParental(1); | |
| 340 | - } | |
| 321 | + if (!ObjectUtils.isEmpty(parentID)) { | |
| 322 | + if (parentID.contains("/")) { | |
| 323 | + String[] parentIdArray = parentID.split("/"); | |
| 324 | + parentID = parentIdArray[parentIdArray.length - 1]; | |
| 325 | + } | |
| 326 | + deviceChannel.setParentId(parentID); | |
| 327 | + }else { | |
| 328 | + if (!ObjectUtils.isEmpty(businessGroupID)) { | |
| 329 | + deviceChannel.setParentId(businessGroupID); | |
| 330 | + } | |
| 331 | + } | |
| 332 | + break; | |
| 333 | + default: | |
| 334 | + // 设备目录 | |
| 335 | + if (!ObjectUtils.isEmpty(manufacturer)) { | |
| 336 | + deviceChannel.setManufacture(manufacturer); | |
| 337 | + } | |
| 338 | + if (!ObjectUtils.isEmpty(model)) { | |
| 339 | + deviceChannel.setModel(model); | |
| 340 | + } | |
| 341 | + if (!ObjectUtils.isEmpty(owner)) { | |
| 342 | + deviceChannel.setOwner(owner); | |
| 343 | + } | |
| 344 | + if (!ObjectUtils.isEmpty(civilCode)) { | |
| 345 | + deviceChannel.setCivilCode(civilCode); | |
| 346 | + } | |
| 347 | + if (!ObjectUtils.isEmpty(businessGroupID)) { | |
| 348 | + deviceChannel.setBusinessGroupId(businessGroupID); | |
| 349 | + } | |
| 341 | 350 | |
| 351 | + // 警区 | |
| 352 | + String block = getText(itemDevice, "Block"); | |
| 353 | + if (!ObjectUtils.isEmpty(block)) { | |
| 354 | + deviceChannel.setBlock(block); | |
| 355 | + } | |
| 356 | + if (!ObjectUtils.isEmpty(address)) { | |
| 357 | + deviceChannel.setAddress(address); | |
| 358 | + } | |
| 342 | 359 | |
| 343 | - deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer")); | |
| 344 | - deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model")); | |
| 345 | - deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner")); | |
| 346 | - deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum")); | |
| 347 | - deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block")); | |
| 348 | - deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address")); | |
| 349 | - deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password")); | |
| 360 | + if (!ObjectUtils.isEmpty(secrecy)) { | |
| 361 | + deviceChannel.setSecrecy(secrecy); | |
| 362 | + } | |
| 350 | 363 | |
| 351 | - String safetyWay = XmlUtil.getText(itemDevice, "SafetyWay"); | |
| 352 | - if (ObjectUtils.isEmpty(safetyWay)) { | |
| 353 | - deviceChannel.setSafetyWay(0); | |
| 354 | - } else { | |
| 355 | - deviceChannel.setSafetyWay(Integer.parseInt(safetyWay)); | |
| 356 | - } | |
| 364 | + // 当为设备时,是否有子设备(必选)1有,0没有 | |
| 365 | + String parental = getText(itemDevice, "Parental"); | |
| 366 | + if (!ObjectUtils.isEmpty(parental)) { | |
| 367 | + try { | |
| 368 | + // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1 | |
| 369 | + if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) { | |
| 370 | + deviceChannel.setParental(0); | |
| 371 | + }else { | |
| 372 | + deviceChannel.setParental(1); | |
| 373 | + } | |
| 374 | + }catch (NumberFormatException e) { | |
| 375 | + logger.warn("[xml解析] 从通道数据获取 parental失败: {}", parental); | |
| 376 | + } | |
| 377 | + } | |
| 378 | + // 父设备/区域/系统ID | |
| 379 | + String realParentId = parentID; | |
| 380 | + if (!ObjectUtils.isEmpty(parentID)) { | |
| 381 | + if (parentID.contains("/")) { | |
| 382 | + String[] parentIdArray = parentID.split("/"); | |
| 383 | + realParentId = parentIdArray[parentIdArray.length - 1]; | |
| 384 | + } | |
| 385 | + deviceChannel.setParentId(realParentId); | |
| 386 | + }else { | |
| 387 | + if (!ObjectUtils.isEmpty(businessGroupID)) { | |
| 388 | + deviceChannel.setParentId(businessGroupID); | |
| 389 | + }else { | |
| 390 | + if (!ObjectUtils.isEmpty(civilCode)) { | |
| 391 | + deviceChannel.setParentId(civilCode); | |
| 392 | + } | |
| 393 | + } | |
| 394 | + } | |
| 395 | + // 注册方式 | |
| 396 | + if (!ObjectUtils.isEmpty(registerWay)) { | |
| 397 | + try { | |
| 398 | + int registerWayInt = Integer.parseInt(registerWay); | |
| 399 | + deviceChannel.setRegisterWay(registerWayInt); | |
| 400 | + }catch (NumberFormatException exception) { | |
| 401 | + logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); | |
| 402 | + deviceChannel.setRegisterWay(1); | |
| 403 | + } | |
| 404 | + }else { | |
| 405 | + deviceChannel.setRegisterWay(1); | |
| 406 | + } | |
| 357 | 407 | |
| 358 | - String registerWay = XmlUtil.getText(itemDevice, "RegisterWay"); | |
| 359 | - if (ObjectUtils.isEmpty(registerWay)) { | |
| 360 | - deviceChannel.setRegisterWay(1); | |
| 361 | - } else { | |
| 362 | - deviceChannel.setRegisterWay(Integer.parseInt(registerWay)); | |
| 363 | - } | |
| 408 | + // 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/MIME加密签名同时采用方式;4:数字摘要方式 | |
| 409 | + String safetyWay = getText(itemDevice, "SafetyWay"); | |
| 410 | + if (!ObjectUtils.isEmpty(safetyWay)) { | |
| 411 | + try { | |
| 412 | + deviceChannel.setSafetyWay(Integer.parseInt(safetyWay)); | |
| 413 | + }catch (NumberFormatException e) { | |
| 414 | + logger.warn("[xml解析] 从通道数据获取 safetyWay失败: {}", safetyWay); | |
| 415 | + } | |
| 416 | + } | |
| 364 | 417 | |
| 365 | - if (XmlUtil.getText(itemDevice, "Certifiable") == null | |
| 366 | - || XmlUtil.getText(itemDevice, "Certifiable") == "") { | |
| 367 | - deviceChannel.setCertifiable(0); | |
| 368 | - } else { | |
| 369 | - deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable"))); | |
| 370 | - } | |
| 418 | + // 证书序列号(有证书的设备必选) | |
| 419 | + String certNum = getText(itemDevice, "CertNum"); | |
| 420 | + if (!ObjectUtils.isEmpty(certNum)) { | |
| 421 | + deviceChannel.setCertNum(certNum); | |
| 422 | + } | |
| 371 | 423 | |
| 372 | - if (XmlUtil.getText(itemDevice, "ErrCode") == null | |
| 373 | - || XmlUtil.getText(itemDevice, "ErrCode") == "") { | |
| 374 | - deviceChannel.setErrCode(0); | |
| 375 | - } else { | |
| 376 | - deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode"))); | |
| 377 | - } | |
| 424 | + // 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1:有效 | |
| 425 | + String certifiable = getText(itemDevice, "Certifiable"); | |
| 426 | + if (!ObjectUtils.isEmpty(certifiable)) { | |
| 427 | + try { | |
| 428 | + deviceChannel.setCertifiable(Integer.parseInt(certifiable)); | |
| 429 | + }catch (NumberFormatException e) { | |
| 430 | + logger.warn("[xml解析] 从通道数据获取 Certifiable失败: {}", certifiable); | |
| 431 | + } | |
| 432 | + } | |
| 378 | 433 | |
| 379 | - deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime")); | |
| 380 | - deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy")); | |
| 381 | - deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress")); | |
| 382 | - if (XmlUtil.getText(itemDevice, "Port") == null || XmlUtil.getText(itemDevice, "Port") == "") { | |
| 383 | - deviceChannel.setPort(0); | |
| 384 | - } else { | |
| 385 | - deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port"))); | |
| 386 | - } | |
| 434 | + // 无效原因码(有证书且证书无效的设备必选) | |
| 435 | + String errCode = getText(itemDevice, "ErrCode"); | |
| 436 | + if (!ObjectUtils.isEmpty(errCode)) { | |
| 437 | + try { | |
| 438 | + deviceChannel.setErrCode(Integer.parseInt(errCode)); | |
| 439 | + }catch (NumberFormatException e) { | |
| 440 | + logger.warn("[xml解析] 从通道数据获取 ErrCode失败: {}", errCode); | |
| 441 | + } | |
| 442 | + } | |
| 387 | 443 | |
| 444 | + // 证书终止有效期(有证书的设备必选) | |
| 445 | + String endTime = getText(itemDevice, "EndTime"); | |
| 446 | + if (!ObjectUtils.isEmpty(endTime)) { | |
| 447 | + deviceChannel.setEndTime(endTime); | |
| 448 | + } | |
| 388 | 449 | |
| 389 | - String longitude = XmlUtil.getText(itemDevice, "Longitude"); | |
| 390 | - if (NumericUtil.isDouble(longitude)) { | |
| 391 | - deviceChannel.setLongitude(Double.parseDouble(longitude)); | |
| 392 | - } else { | |
| 393 | - deviceChannel.setLongitude(0.00); | |
| 394 | - } | |
| 395 | - String latitude = XmlUtil.getText(itemDevice, "Latitude"); | |
| 396 | - if (NumericUtil.isDouble(latitude)) { | |
| 397 | - deviceChannel.setLatitude(Double.parseDouble(latitude)); | |
| 398 | - } else { | |
| 399 | - deviceChannel.setLatitude(0.00); | |
| 400 | - } | |
| 401 | 450 | |
| 402 | - deviceChannel.setGpsTime(DateUtil.getNow()); | |
| 451 | + // 设备/区域/系统IP地址 | |
| 452 | + String ipAddress = getText(itemDevice, "IPAddress"); | |
| 453 | + if (!ObjectUtils.isEmpty(ipAddress)) { | |
| 454 | + deviceChannel.setIpAddress(ipAddress); | |
| 455 | + } | |
| 456 | + | |
| 457 | + // 设备/区域/系统端口 | |
| 458 | + String port = getText(itemDevice, "Port"); | |
| 459 | + if (!ObjectUtils.isEmpty(port)) { | |
| 460 | + try { | |
| 461 | + deviceChannel.setPort(Integer.parseInt(port)); | |
| 462 | + }catch (NumberFormatException e) { | |
| 463 | + logger.warn("[xml解析] 从通道数据获取 Port失败: {}", port); | |
| 464 | + } | |
| 465 | + } | |
| 466 | + | |
| 467 | + // 设备口令 | |
| 468 | + String password = getText(itemDevice, "Password"); | |
| 469 | + if (!ObjectUtils.isEmpty(password)) { | |
| 470 | + deviceChannel.setPassword(password); | |
| 471 | + } | |
| 403 | 472 | |
| 404 | 473 | |
| 405 | - if (XmlUtil.getText(itemDevice, "PTZType") == null || "".equals(XmlUtil.getText(itemDevice, "PTZType"))) { | |
| 406 | - //兼容INFO中的信息 | |
| 407 | - Element info = itemDevice.element("Info"); | |
| 408 | - if(XmlUtil.getText(info, "PTZType") == null || "".equals(XmlUtil.getText(info, "PTZType"))){ | |
| 409 | - deviceChannel.setPTZType(0); | |
| 410 | - }else{ | |
| 411 | - deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(info, "PTZType"))); | |
| 474 | + // 设备状态 | |
| 475 | + String status = getText(itemDevice, "Status"); | |
| 476 | + if (status != null) { | |
| 477 | + // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 | |
| 478 | + if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) { | |
| 479 | + deviceChannel.setStatus(true); | |
| 480 | + } | |
| 481 | + if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { | |
| 482 | + deviceChannel.setStatus(false); | |
| 483 | + } | |
| 484 | + }else { | |
| 485 | + deviceChannel.setStatus(true); | |
| 486 | + } | |
| 487 | + | |
| 488 | + // 经度 | |
| 489 | + String longitude = getText(itemDevice, "Longitude"); | |
| 490 | + if (NumericUtil.isDouble(longitude)) { | |
| 491 | + deviceChannel.setLongitude(Double.parseDouble(longitude)); | |
| 492 | + } else { | |
| 493 | + deviceChannel.setLongitude(0.00); | |
| 494 | + } | |
| 495 | + | |
| 496 | + // 纬度 | |
| 497 | + String latitude = getText(itemDevice, "Latitude"); | |
| 498 | + if (NumericUtil.isDouble(latitude)) { | |
| 499 | + deviceChannel.setLatitude(Double.parseDouble(latitude)); | |
| 500 | + } else { | |
| 501 | + deviceChannel.setLatitude(0.00); | |
| 502 | + } | |
| 503 | + | |
| 504 | + deviceChannel.setGpsTime(DateUtil.getNow()); | |
| 505 | + | |
| 506 | + // -摄像机类型扩展,标识摄像机类型:1-球机;2-半球;3-固定枪机;4-遥控枪机。当目录项为摄像机时可选 | |
| 507 | + String ptzType = getText(itemDevice, "PTZType"); | |
| 508 | + if (ObjectUtils.isEmpty(ptzType)) { | |
| 509 | + //兼容INFO中的信息 | |
| 510 | + Element info = itemDevice.element("Info"); | |
| 511 | + String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType"); | |
| 512 | + if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){ | |
| 513 | + try { | |
| 514 | + deviceChannel.setPTZType(Integer.parseInt(ptzTypeFromInfo)); | |
| 515 | + }catch (NumberFormatException e){ | |
| 516 | + logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo); | |
| 517 | + } | |
| 518 | + } | |
| 519 | + } else { | |
| 520 | + try { | |
| 521 | + deviceChannel.setPTZType(Integer.parseInt(ptzType)); | |
| 522 | + }catch (NumberFormatException e){ | |
| 523 | + logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType); | |
| 524 | + } | |
| 525 | + } | |
| 526 | + | |
| 527 | + // TODO 摄像机位置类型扩展。 | |
| 528 | + // 1-省际检查站、 | |
| 529 | + // 2-党政机关、 | |
| 530 | + // 3-车站码头、 | |
| 531 | + // 4-中心广场、 | |
| 532 | + // 5-体育场馆、 | |
| 533 | + // 6-商业中心、 | |
| 534 | + // 7-宗教场所、 | |
| 535 | + // 8-校园周边、 | |
| 536 | + // 9-治安复杂区域、 | |
| 537 | + // 10-交通干线。 | |
| 538 | + // String positionType = getText(itemDevice, "PositionType"); | |
| 539 | + | |
| 540 | + // TODO 摄像机安装位置室外、室内属性。1-室外、2-室内。 | |
| 541 | + // String roomType = getText(itemDevice, "RoomType"); | |
| 542 | + // TODO 摄像机用途属性 | |
| 543 | + // String useType = getText(itemDevice, "UseType"); | |
| 544 | + // TODO 摄像机补光属性。1-无补光、2-红外补光、3-白光补光 | |
| 545 | + // String supplyLightType = getText(itemDevice, "SupplyLightType"); | |
| 546 | + // TODO 摄像机监视方位属性。1-东、2-西、3-南、4-北、5-东南、6-东北、7-西南、8-西北。 | |
| 547 | + // String directionType = getText(itemDevice, "DirectionType"); | |
| 548 | + // TODO 摄像机支持的分辨率,可有多个分辨率值,各个取值间以“/”分隔。分辨率取值参见附录 F中SDPf字段规定 | |
| 549 | + // String resolution = getText(itemDevice, "Resolution"); | |
| 550 | + | |
| 551 | + // TODO 下载倍速范围(可选),各可选参数以“/”分隔,如设备支持1,2,4倍速下载则应写为“1/2/4 | |
| 552 | + // String downloadSpeed = getText(itemDevice, "DownloadSpeed"); | |
| 553 | + // TODO 空域编码能力,取值0:不支持;1:1级增强(1个增强层);2:2级增强(2个增强层);3:3级增强(3个增强层) | |
| 554 | + // String svcSpaceSupportMode = getText(itemDevice, "SVCSpaceSupportMode"); | |
| 555 | + // TODO 时域编码能力,取值0:不支持;1:1级增强;2:2级增强;3:3级增强 | |
| 556 | + // String svcTimeSupportMode = getText(itemDevice, "SVCTimeSupportMode"); | |
| 557 | + | |
| 558 | + | |
| 559 | + deviceChannel.setSecrecy(secrecy); | |
| 560 | + break; | |
| 412 | 561 | } |
| 413 | - } else { | |
| 414 | - deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType"))); | |
| 415 | 562 | } |
| 416 | 563 | |
| 417 | 564 | return deviceChannel; | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| ... | ... | @@ -131,14 +131,12 @@ public class ZLMHttpHookListener { |
| 131 | 131 | @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8") |
| 132 | 132 | public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) { |
| 133 | 133 | |
| 134 | -// logger.info("[ZLM HOOK] 收到zlm心跳:" + param.getMediaServerId()); | |
| 135 | 134 | |
| 136 | 135 | taskExecutor.execute(() -> { |
| 137 | 136 | List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive); |
| 138 | - JSONObject json = (JSONObject) JSON.toJSON(param); | |
| 139 | 137 | if (subscribes != null && subscribes.size() > 0) { |
| 140 | 138 | for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { |
| 141 | - subscribe.response(null, json); | |
| 139 | + subscribe.response(null, param); | |
| 142 | 140 | } |
| 143 | 141 | } |
| 144 | 142 | }); |
| ... | ... | @@ -165,7 +163,7 @@ public class ZLMHttpHookListener { |
| 165 | 163 | if (subscribe != null) { |
| 166 | 164 | MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); |
| 167 | 165 | if (mediaInfo != null) { |
| 168 | - subscribe.response(mediaInfo, json); | |
| 166 | + subscribe.response(mediaInfo, param); | |
| 169 | 167 | } |
| 170 | 168 | } |
| 171 | 169 | }); |
| ... | ... | @@ -198,13 +196,13 @@ public class ZLMHttpHookListener { |
| 198 | 196 | if (userSetting.getPushAuthority()) { |
| 199 | 197 | // 推流鉴权 |
| 200 | 198 | if (param.getParams() == null) { |
| 201 | - logger.info("推流鉴权失败: 缺少不要参数:sign=md5(user表的pushKey)"); | |
| 199 | + logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)"); | |
| 202 | 200 | return new HookResultForOnPublish(401, "Unauthorized"); |
| 203 | 201 | } |
| 204 | 202 | Map<String, String> paramMap = urlParamToMap(param.getParams()); |
| 205 | 203 | String sign = paramMap.get("sign"); |
| 206 | 204 | if (sign == null) { |
| 207 | - logger.info("推流鉴权失败: 缺少不要参数:sign=md5(user表的pushKey)"); | |
| 205 | + logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)"); | |
| 208 | 206 | return new HookResultForOnPublish(401, "Unauthorized"); |
| 209 | 207 | } |
| 210 | 208 | // 推流自定义播放鉴权码 |
| ... | ... | @@ -241,7 +239,7 @@ public class ZLMHttpHookListener { |
| 241 | 239 | ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json); |
| 242 | 240 | if (subscribe != null) { |
| 243 | 241 | if (mediaInfo != null) { |
| 244 | - subscribe.response(mediaInfo, json); | |
| 242 | + subscribe.response(mediaInfo, param); | |
| 245 | 243 | } else { |
| 246 | 244 | new HookResultForOnPublish(1, "zlm not register"); |
| 247 | 245 | } |
| ... | ... | @@ -321,7 +319,7 @@ public class ZLMHttpHookListener { |
| 321 | 319 | return; |
| 322 | 320 | } |
| 323 | 321 | if (subscribe != null) { |
| 324 | - subscribe.response(mediaInfo, json); | |
| 322 | + subscribe.response(mediaInfo, param); | |
| 325 | 323 | } |
| 326 | 324 | |
| 327 | 325 | List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks(); |
| ... | ... | @@ -551,7 +549,9 @@ public class ZLMHttpHookListener { |
| 551 | 549 | Device device = deviceService.getDevice(inviteInfo.getDeviceId()); |
| 552 | 550 | if (device != null) { |
| 553 | 551 | try { |
| 554 | - if (inviteStreamService.getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream()) != null) { | |
| 552 | + InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(), | |
| 553 | + inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream()); | |
| 554 | + if (info != null) { | |
| 555 | 555 | cmder.streamByeCmd(device, inviteInfo.getChannelId(), |
| 556 | 556 | inviteInfo.getStream(), null); |
| 557 | 557 | } |
| ... | ... | @@ -578,13 +578,13 @@ public class ZLMHttpHookListener { |
| 578 | 578 | // 拉流代理 |
| 579 | 579 | StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); |
| 580 | 580 | if (streamProxyItem != null) { |
| 581 | - if (streamProxyItem.isEnable_remove_none_reader()) { | |
| 581 | + if (streamProxyItem.isEnableDisableNoneReader()) { | |
| 582 | 582 | // 无人观看自动移除 |
| 583 | 583 | ret.put("close", true); |
| 584 | 584 | streamProxyService.del(param.getApp(), param.getStream()); |
| 585 | - String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrc_url(); | |
| 585 | + String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrcUrl(); | |
| 586 | 586 | logger.info("[{}/{}]<-[{}] 拉流代理无人观看已经移除", param.getApp(), param.getStream(), url); |
| 587 | - } else if (streamProxyItem.isEnable_disable_none_reader()) { | |
| 587 | + } else if (streamProxyItem.isEnableDisableNoneReader()) { | |
| 588 | 588 | // 无人观看停用 |
| 589 | 589 | ret.put("close", true); |
| 590 | 590 | // 修改数据 |
| ... | ... | @@ -669,7 +669,7 @@ public class ZLMHttpHookListener { |
| 669 | 669 | } else { |
| 670 | 670 | // 拉流代理 |
| 671 | 671 | StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream()); |
| 672 | - if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnable_disable_none_reader()) { | |
| 672 | + if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnableDisableNoneReader()) { | |
| 673 | 673 | streamProxyService.start(param.getApp(), param.getStream()); |
| 674 | 674 | } |
| 675 | 675 | DeferredResult<HookResult> result = new DeferredResult<>(); |
| ... | ... | @@ -693,7 +693,7 @@ public class ZLMHttpHookListener { |
| 693 | 693 | List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started); |
| 694 | 694 | if (subscribes != null && subscribes.size() > 0) { |
| 695 | 695 | for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { |
| 696 | - subscribe.response(null, jsonObject); | |
| 696 | + subscribe.response(null, zlmServerConfig); | |
| 697 | 697 | } |
| 698 | 698 | } |
| 699 | 699 | mediaServerService.zlmServerOnline(zlmServerConfig); |
| ... | ... | @@ -749,7 +749,7 @@ public class ZLMHttpHookListener { |
| 749 | 749 | List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout); |
| 750 | 750 | if (subscribes != null && subscribes.size() > 0) { |
| 751 | 751 | for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { |
| 752 | - subscribe.response(null, json); | |
| 752 | + subscribe.response(null, param); | |
| 753 | 753 | } |
| 754 | 754 | } |
| 755 | 755 | }); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
| ... | ... | @@ -157,7 +157,6 @@ public class ZLMRESTfulUtils { |
| 157 | 157 | |
| 158 | 158 | public void sendGetForImg(MediaServerItem mediaServerItem, String api, Map<String, Object> params, String targetPath, String fileName) { |
| 159 | 159 | String url = String.format("http://%s:%s/index/api/%s", mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api); |
| 160 | - logger.debug(url); | |
| 161 | 160 | HttpUrl parseUrl = HttpUrl.parse(url); |
| 162 | 161 | if (parseUrl == null) { |
| 163 | 162 | return; | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
| ... | ... | @@ -9,6 +9,11 @@ import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; |
| 9 | 9 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; |
| 10 | 10 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout; |
| 11 | 11 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 12 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; | |
| 13 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRtpServerTimeoutHookParam; | |
| 14 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; | |
| 15 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout; | |
| 16 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | |
| 12 | 17 | import org.slf4j.Logger; |
| 13 | 18 | import org.slf4j.LoggerFactory; |
| 14 | 19 | import org.springframework.beans.factory.annotation.Autowired; |
| ... | ... | @@ -228,7 +233,7 @@ public class ZLMRTPServerFactory { |
| 228 | 233 | int localPort = 0; |
| 229 | 234 | if (userSetting.getGbSendStreamStrict()) { |
| 230 | 235 | if (userSetting.getGbSendStreamStrict()) { |
| 231 | - localPort = keepPort(serverItem, ssrc, null); | |
| 236 | + localPort = keepPort(serverItem, ssrc, localPort); | |
| 232 | 237 | if (localPort == 0) { |
| 233 | 238 | return null; |
| 234 | 239 | } |
| ... | ... | @@ -264,7 +269,7 @@ public class ZLMRTPServerFactory { |
| 264 | 269 | // 默认为随机端口 |
| 265 | 270 | int localPort = 0; |
| 266 | 271 | if (userSetting.getGbSendStreamStrict()) { |
| 267 | - localPort = keepPort(serverItem, ssrc, null); | |
| 272 | + localPort = keepPort(serverItem, ssrc, localPort); | |
| 268 | 273 | if (localPort == 0) { |
| 269 | 274 | return null; |
| 270 | 275 | } |
| ... | ... | @@ -290,9 +295,6 @@ public class ZLMRTPServerFactory { |
| 290 | 295 | */ |
| 291 | 296 | public int keepPort(MediaServerItem serverItem, String ssrc, Integer localPort) { |
| 292 | 297 | Map<String, Object> param = new HashMap<>(3); |
| 293 | - if (localPort == null) { | |
| 294 | - localPort = 0; | |
| 295 | - } | |
| 296 | 298 | param.put("port", localPort); |
| 297 | 299 | param.put("enable_tcp", 1); |
| 298 | 300 | param.put("stream_id", ssrc); |
| ... | ... | @@ -302,22 +304,24 @@ public class ZLMRTPServerFactory { |
| 302 | 304 | HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(ssrc, null, serverItem.getId()); |
| 303 | 305 | Integer finalLocalPort = localPort; |
| 304 | 306 | hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout, |
| 305 | - (MediaServerItem mediaServerItem, JSONObject response)->{ | |
| 306 | - if (ssrc.equals(response.getString("ssrc"))) { | |
| 307 | - logger.info("[上级点播] {}->监听端口到期继续保持监听", ssrc); | |
| 308 | - int port = keepPort(serverItem, ssrc, finalLocalPort); | |
| 309 | - if (port == 0) { | |
| 310 | - logger.info("[上级点播] {}->监听端口失败,移除监听", ssrc); | |
| 311 | - hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout); | |
| 312 | - } | |
| 307 | + (MediaServerItem mediaServerItem, HookParam hookParam)->{ | |
| 308 | + logger.info("[上级点播] {}->监听端口到期继续保持监听: {}", ssrc, finalLocalPort); | |
| 309 | + OnRtpServerTimeoutHookParam rtpServerTimeoutHookParam = (OnRtpServerTimeoutHookParam) hookParam; | |
| 310 | + if (!ssrc.equals(rtpServerTimeoutHookParam.getSsrc())) { | |
| 311 | + return; | |
| 312 | + } | |
| 313 | + int port = keepPort(serverItem, ssrc, finalLocalPort); | |
| 314 | + if (port == 0) { | |
| 315 | + logger.info("[上级点播] {}->监听端口失败,移除监听", ssrc); | |
| 316 | + hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout); | |
| 313 | 317 | } |
| 314 | 318 | }); |
| 315 | - logger.info("[保持端口] {}->监听端口: {}", ssrc, localPort); | |
| 316 | - logger.info("[保持端口] {}->监听端口: {}", ssrc, localPort); | |
| 319 | + logger.info("[上级点播] {}->监听端口: {}", ssrc, localPort); | |
| 320 | + return localPort; | |
| 317 | 321 | }else { |
| 318 | - logger.info("[保持端口] 监听端口失败: {}", ssrc); | |
| 322 | + logger.info("[上级点播] 监听端口失败: {}->{}", ssrc, localPort); | |
| 323 | + return 0; | |
| 319 | 324 | } |
| 320 | - return localPort; | |
| 321 | 325 | } |
| 322 | 326 | |
| 323 | 327 | /** | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
| ... | ... | @@ -65,8 +65,8 @@ public class ZLMRunner implements CommandLineRunner { |
| 65 | 65 | HookSubscribeForServerStarted hookSubscribeForServerStarted = HookSubscribeFactory.on_server_started(); |
| 66 | 66 | // 订阅 zlm启动事件, 新的zlm也会从这里进入系统 |
| 67 | 67 | hookSubscribe.addSubscribe(hookSubscribeForServerStarted, |
| 68 | - (MediaServerItem mediaServerItem, JSONObject response)->{ | |
| 69 | - ZLMServerConfig zlmServerConfig = response.to(ZLMServerConfig.class); | |
| 68 | + (mediaServerItem, hookParam)->{ | |
| 69 | + ZLMServerConfig zlmServerConfig = (ZLMServerConfig)hookParam; | |
| 70 | 70 | if (zlmServerConfig !=null ) { |
| 71 | 71 | if (startGetMedia != null) { |
| 72 | 72 | startGetMedia.remove(zlmServerConfig.getGeneralMediaServerId()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java
| 1 | 1 | package com.genersoft.iot.vmp.media.zlm; |
| 2 | 2 | |
| 3 | 3 | import com.alibaba.fastjson2.annotation.JSONField; |
| 4 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; | |
| 4 | 5 | |
| 5 | -public class ZLMServerConfig { | |
| 6 | +public class ZLMServerConfig extends HookParam { | |
| 6 | 7 | |
| 7 | 8 | @JSONField(name = "api.apiDebug") |
| 8 | 9 | private String apiDebug; | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZlmHttpHookSubscribe.java
| ... | ... | @@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSONObject; |
| 4 | 4 | import com.genersoft.iot.vmp.media.zlm.dto.HookType; |
| 5 | 5 | import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe; |
| 6 | 6 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 7 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; | |
| 7 | 8 | import org.slf4j.Logger; |
| 8 | 9 | import org.slf4j.LoggerFactory; |
| 9 | 10 | import org.springframework.scheduling.annotation.Scheduled; |
| ... | ... | @@ -26,7 +27,7 @@ public class ZlmHttpHookSubscribe { |
| 26 | 27 | |
| 27 | 28 | @FunctionalInterface |
| 28 | 29 | public interface Event{ |
| 29 | - void response(MediaServerItem mediaServerItem, JSONObject response); | |
| 30 | + void response(MediaServerItem mediaServerItem, HookParam hookParam); | |
| 30 | 31 | } |
| 31 | 32 | |
| 32 | 33 | private Map<HookType, Map<IHookSubscribe, ZlmHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
| ... | ... | @@ -20,28 +20,26 @@ public class StreamProxyItem extends GbStream { |
| 20 | 20 | @Schema(description = "拉流地址") |
| 21 | 21 | private String url; |
| 22 | 22 | @Schema(description = "拉流地址") |
| 23 | - private String src_url; | |
| 23 | + private String srcUrl; | |
| 24 | 24 | @Schema(description = "目标地址") |
| 25 | - private String dst_url; | |
| 25 | + private String dstUrl; | |
| 26 | 26 | @Schema(description = "超时时间") |
| 27 | - private int timeout_ms; | |
| 27 | + private int timeoutMs; | |
| 28 | 28 | @Schema(description = "ffmpeg模板KEY") |
| 29 | - private String ffmpeg_cmd_key; | |
| 29 | + private String ffmpegCmdKey; | |
| 30 | 30 | @Schema(description = "rtsp拉流时,拉流方式,0:tcp,1:udp,2:组播") |
| 31 | - private String rtp_type; | |
| 31 | + private String rtpType; | |
| 32 | 32 | @Schema(description = "是否启用") |
| 33 | 33 | private boolean enable; |
| 34 | 34 | @Schema(description = "是否启用音频") |
| 35 | - private boolean enable_audio; | |
| 35 | + private boolean enableAudio; | |
| 36 | 36 | @Schema(description = "是否启用MP4") |
| 37 | - private boolean enable_mp4; | |
| 37 | + private boolean enableMp4; | |
| 38 | 38 | @Schema(description = "是否 无人观看时删除") |
| 39 | - private boolean enable_remove_none_reader; | |
| 39 | + private boolean enableRemoveNoneReader; | |
| 40 | 40 | |
| 41 | 41 | @Schema(description = "是否 无人观看时自动停用") |
| 42 | - private boolean enable_disable_none_reader; | |
| 43 | - @Schema(description = "创建时间") | |
| 44 | - private String createTime; | |
| 42 | + private boolean enableDisableNoneReader; | |
| 45 | 43 | |
| 46 | 44 | public String getType() { |
| 47 | 45 | return type; |
| ... | ... | @@ -89,44 +87,44 @@ public class StreamProxyItem extends GbStream { |
| 89 | 87 | this.url = url; |
| 90 | 88 | } |
| 91 | 89 | |
| 92 | - public String getSrc_url() { | |
| 93 | - return src_url; | |
| 90 | + public String getSrcUrl() { | |
| 91 | + return srcUrl; | |
| 94 | 92 | } |
| 95 | 93 | |
| 96 | - public void setSrc_url(String src_url) { | |
| 97 | - this.src_url = src_url; | |
| 94 | + public void setSrcUrl(String src_url) { | |
| 95 | + this.srcUrl = src_url; | |
| 98 | 96 | } |
| 99 | 97 | |
| 100 | - public String getDst_url() { | |
| 101 | - return dst_url; | |
| 98 | + public String getDstUrl() { | |
| 99 | + return dstUrl; | |
| 102 | 100 | } |
| 103 | 101 | |
| 104 | - public void setDst_url(String dst_url) { | |
| 105 | - this.dst_url = dst_url; | |
| 102 | + public void setDstUrl(String dst_url) { | |
| 103 | + this.dstUrl = dst_url; | |
| 106 | 104 | } |
| 107 | 105 | |
| 108 | - public int getTimeout_ms() { | |
| 109 | - return timeout_ms; | |
| 106 | + public int getTimeoutMs() { | |
| 107 | + return timeoutMs; | |
| 110 | 108 | } |
| 111 | 109 | |
| 112 | - public void setTimeout_ms(int timeout_ms) { | |
| 113 | - this.timeout_ms = timeout_ms; | |
| 110 | + public void setTimeoutMs(int timeout_ms) { | |
| 111 | + this.timeoutMs = timeout_ms; | |
| 114 | 112 | } |
| 115 | 113 | |
| 116 | - public String getFfmpeg_cmd_key() { | |
| 117 | - return ffmpeg_cmd_key; | |
| 114 | + public String getFfmpegCmdKey() { | |
| 115 | + return ffmpegCmdKey; | |
| 118 | 116 | } |
| 119 | 117 | |
| 120 | - public void setFfmpeg_cmd_key(String ffmpeg_cmd_key) { | |
| 121 | - this.ffmpeg_cmd_key = ffmpeg_cmd_key; | |
| 118 | + public void setFfmpegCmdKey(String ffmpeg_cmd_key) { | |
| 119 | + this.ffmpegCmdKey = ffmpeg_cmd_key; | |
| 122 | 120 | } |
| 123 | 121 | |
| 124 | - public String getRtp_type() { | |
| 125 | - return rtp_type; | |
| 122 | + public String getRtpType() { | |
| 123 | + return rtpType; | |
| 126 | 124 | } |
| 127 | 125 | |
| 128 | - public void setRtp_type(String rtp_type) { | |
| 129 | - this.rtp_type = rtp_type; | |
| 126 | + public void setRtpType(String rtp_type) { | |
| 127 | + this.rtpType = rtp_type; | |
| 130 | 128 | } |
| 131 | 129 | |
| 132 | 130 | public boolean isEnable() { |
| ... | ... | @@ -137,45 +135,37 @@ public class StreamProxyItem extends GbStream { |
| 137 | 135 | this.enable = enable; |
| 138 | 136 | } |
| 139 | 137 | |
| 140 | - public boolean isEnable_mp4() { | |
| 141 | - return enable_mp4; | |
| 138 | + public boolean isEnableMp4() { | |
| 139 | + return enableMp4; | |
| 142 | 140 | } |
| 143 | 141 | |
| 144 | - public void setEnable_mp4(boolean enable_mp4) { | |
| 145 | - this.enable_mp4 = enable_mp4; | |
| 142 | + public void setEnableMp4(boolean enable_mp4) { | |
| 143 | + this.enableMp4 = enable_mp4; | |
| 146 | 144 | } |
| 147 | 145 | |
| 148 | - @Override | |
| 149 | - public String getCreateTime() { | |
| 150 | - return createTime; | |
| 146 | + public boolean isEnableRemoveNoneReader() { | |
| 147 | + return enableRemoveNoneReader; | |
| 151 | 148 | } |
| 152 | 149 | |
| 153 | - @Override | |
| 154 | - public void setCreateTime(String createTime) { | |
| 155 | - this.createTime = createTime; | |
| 150 | + public void setEnableRemoveNoneReader(boolean enable_remove_none_reader) { | |
| 151 | + this.enableRemoveNoneReader = enable_remove_none_reader; | |
| 156 | 152 | } |
| 157 | 153 | |
| 158 | - public boolean isEnable_remove_none_reader() { | |
| 159 | - return enable_remove_none_reader; | |
| 154 | + public boolean isEnableDisableNoneReader() { | |
| 155 | + return enableDisableNoneReader; | |
| 160 | 156 | } |
| 161 | 157 | |
| 162 | - public void setEnable_remove_none_reader(boolean enable_remove_none_reader) { | |
| 163 | - this.enable_remove_none_reader = enable_remove_none_reader; | |
| 158 | + public void setEnableDisableNoneReader(boolean enable_disable_none_reader) { | |
| 159 | + this.enableDisableNoneReader = enable_disable_none_reader; | |
| 164 | 160 | } |
| 165 | 161 | |
| 166 | - public boolean isEnable_disable_none_reader() { | |
| 167 | - return enable_disable_none_reader; | |
| 162 | + public boolean isEnableAudio() { | |
| 163 | + return enableAudio; | |
| 168 | 164 | } |
| 169 | 165 | |
| 170 | - public void setEnable_disable_none_reader(boolean enable_disable_none_reader) { | |
| 171 | - this.enable_disable_none_reader = enable_disable_none_reader; | |
| 166 | + public void setEnableAudio(boolean enable_audio) { | |
| 167 | + this.enableAudio = enable_audio; | |
| 172 | 168 | } |
| 173 | 169 | |
| 174 | - public boolean isEnable_audio() { | |
| 175 | - return enable_audio; | |
| 176 | - } | |
| 177 | 170 | |
| 178 | - public void setEnable_audio(boolean enable_audio) { | |
| 179 | - this.enable_audio = enable_audio; | |
| 180 | - } | |
| 181 | 171 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java
| ... | ... | @@ -325,5 +325,65 @@ public class StreamPushItem extends GbStream implements Comparable<StreamPushIte |
| 325 | 325 | public void setSelf(boolean self) { |
| 326 | 326 | this.self = self; |
| 327 | 327 | } |
| 328 | + | |
| 329 | +// @Override | |
| 330 | +// public Integer getGbStreamId() { | |
| 331 | +// return super.getGbStreamId(); | |
| 332 | +// } | |
| 333 | +// | |
| 334 | +// @Override | |
| 335 | +// public void setGbStreamId(Integer gbStreamId) { | |
| 336 | +// super.setGbStreamId(gbStreamId); | |
| 337 | +// } | |
| 338 | +// | |
| 339 | +// | |
| 340 | +// public String getGbId() { | |
| 341 | +// return super.getGbId(); | |
| 342 | +// } | |
| 343 | +// | |
| 344 | +// public void setGbId(String gbId) { | |
| 345 | +// super.setGbId(gbId); | |
| 346 | +// } | |
| 347 | +// | |
| 348 | +// public String getName() { | |
| 349 | +// return super.getName(); | |
| 350 | +// } | |
| 351 | +// | |
| 352 | +// public void setName(String name) { | |
| 353 | +// super.setName(name); | |
| 354 | +// } | |
| 355 | +// | |
| 356 | +// public double getLongitude() { | |
| 357 | +// return super.getLongitude(); | |
| 358 | +// } | |
| 359 | +// | |
| 360 | +// public void setLongitude(double longitude) { | |
| 361 | +// super.setLongitude(longitude); | |
| 362 | +// } | |
| 363 | +// | |
| 364 | +// public double getLatitude() { | |
| 365 | +// return super.getLatitude(); | |
| 366 | +// } | |
| 367 | +// | |
| 368 | +// public void setLatitude(double latitude) { | |
| 369 | +// super.setLatitude(latitude); | |
| 370 | +// } | |
| 371 | +// | |
| 372 | +// public String getStreamType() { | |
| 373 | +// return super.getStreamType(); | |
| 374 | +// } | |
| 375 | +// | |
| 376 | +// public void setStreamType(String streamType) { | |
| 377 | +// super.setStreamType(streamType); | |
| 378 | +// } | |
| 379 | +// | |
| 380 | +// public boolean isStatus() { | |
| 381 | +// return super.isStatus(); | |
| 382 | +// } | |
| 383 | +// | |
| 384 | +// public void setStatus(boolean status) { | |
| 385 | +// super.setStatus(status); | |
| 386 | +// } | |
| 387 | + | |
| 328 | 388 | } |
| 329 | 389 | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPlayHookParam.java
| ... | ... | @@ -81,6 +81,15 @@ public class OnPlayHookParam extends HookParam{ |
| 81 | 81 | |
| 82 | 82 | @Override |
| 83 | 83 | public String toString() { |
| 84 | - return String.format("%s://%s:%s/%s/%s?%s", schema, ip, port, app, stream, params); | |
| 84 | + return "OnPlayHookParam{" + | |
| 85 | + "id='" + id + '\'' + | |
| 86 | + ", app='" + app + '\'' + | |
| 87 | + ", stream='" + stream + '\'' + | |
| 88 | + ", ip='" + ip + '\'' + | |
| 89 | + ", params='" + params + '\'' + | |
| 90 | + ", port=" + port + | |
| 91 | + ", schema='" + schema + '\'' + | |
| 92 | + ", vhost='" + vhost + '\'' + | |
| 93 | + '}'; | |
| 85 | 94 | } |
| 86 | 95 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPublishHookParam.java
| ... | ... | @@ -81,6 +81,15 @@ public class OnPublishHookParam extends HookParam{ |
| 81 | 81 | |
| 82 | 82 | @Override |
| 83 | 83 | public String toString() { |
| 84 | - return String.format("%s://%s:%s/%s/%s?%s", schema, ip, port, app, stream, params); | |
| 84 | + return "OnPublishHookParam{" + | |
| 85 | + "id='" + id + '\'' + | |
| 86 | + ", app='" + app + '\'' + | |
| 87 | + ", stream='" + stream + '\'' + | |
| 88 | + ", ip='" + ip + '\'' + | |
| 89 | + ", params='" + params + '\'' + | |
| 90 | + ", port=" + port + | |
| 91 | + ", schema='" + schema + '\'' + | |
| 92 | + ", vhost='" + vhost + '\'' + | |
| 93 | + '}'; | |
| 85 | 94 | } |
| 86 | 95 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRtpServerTimeoutHookParam.java
| ... | ... | @@ -50,4 +50,15 @@ public class OnRtpServerTimeoutHookParam extends HookParam{ |
| 50 | 50 | public void setSsrc(String ssrc) { |
| 51 | 51 | this.ssrc = ssrc; |
| 52 | 52 | } |
| 53 | + | |
| 54 | + @Override | |
| 55 | + public String toString() { | |
| 56 | + return "OnRtpServerTimeoutHookParam{" + | |
| 57 | + "local_port=" + local_port + | |
| 58 | + ", stream_id='" + stream_id + '\'' + | |
| 59 | + ", tcpMode=" + tcpMode + | |
| 60 | + ", re_use_port=" + re_use_port + | |
| 61 | + ", ssrc='" + ssrc + '\'' + | |
| 62 | + '}'; | |
| 63 | + } | |
| 53 | 64 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnSendRtpStoppedHookParam.java
| ... | ... | @@ -24,4 +24,12 @@ public class OnSendRtpStoppedHookParam extends HookParam{ |
| 24 | 24 | public void setStream(String stream) { |
| 25 | 25 | this.stream = stream; |
| 26 | 26 | } |
| 27 | + | |
| 28 | + @Override | |
| 29 | + public String toString() { | |
| 30 | + return "OnSendRtpStoppedHookParam{" + | |
| 31 | + "app='" + app + '\'' + | |
| 32 | + ", stream='" + stream + '\'' + | |
| 33 | + '}'; | |
| 34 | + } | |
| 27 | 35 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnServerKeepaliveHookParam.java
| ... | ... | @@ -17,4 +17,11 @@ public class OnServerKeepaliveHookParam extends HookParam{ |
| 17 | 17 | public void setData(ServerKeepaliveData data) { |
| 18 | 18 | this.data = data; |
| 19 | 19 | } |
| 20 | + | |
| 21 | + @Override | |
| 22 | + public String toString() { | |
| 23 | + return "OnServerKeepaliveHookParam{" + | |
| 24 | + "data=" + data + | |
| 25 | + '}'; | |
| 26 | + } | |
| 20 | 27 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java
| ... | ... | @@ -430,4 +430,14 @@ public class OnStreamChangedHookParam extends HookParam{ |
| 430 | 430 | public void setCallId(String callId) { |
| 431 | 431 | this.callId = callId; |
| 432 | 432 | } |
| 433 | + | |
| 434 | + @Override | |
| 435 | + public String toString() { | |
| 436 | + return "OnStreamChangedHookParam{" + | |
| 437 | + "regist=" + regist + | |
| 438 | + ", app='" + app + '\'' + | |
| 439 | + ", stream='" + stream + '\'' + | |
| 440 | + ", severId='" + severId + '\'' + | |
| 441 | + '}'; | |
| 442 | + } | |
| 433 | 443 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNoneReaderHookParam.java
| ... | ... | @@ -38,4 +38,14 @@ public class OnStreamNoneReaderHookParam extends HookParam{ |
| 38 | 38 | public void setVhost(String vhost) { |
| 39 | 39 | this.vhost = vhost; |
| 40 | 40 | } |
| 41 | + | |
| 42 | + @Override | |
| 43 | + public String toString() { | |
| 44 | + return "OnStreamNoneReaderHookParam{" + | |
| 45 | + "schema='" + schema + '\'' + | |
| 46 | + ", app='" + app + '\'' + | |
| 47 | + ", stream='" + stream + '\'' + | |
| 48 | + ", vhost='" + vhost + '\'' + | |
| 49 | + '}'; | |
| 50 | + } | |
| 41 | 51 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNotFoundHookParam.java
| ... | ... | @@ -81,6 +81,15 @@ public class OnStreamNotFoundHookParam extends HookParam{ |
| 81 | 81 | |
| 82 | 82 | @Override |
| 83 | 83 | public String toString() { |
| 84 | - return String.format("%s://%s:%s/%s/%s?%s", schema, ip, port, app, stream, params); | |
| 84 | + return "OnStreamNotFoundHookParam{" + | |
| 85 | + "id='" + id + '\'' + | |
| 86 | + ", app='" + app + '\'' + | |
| 87 | + ", stream='" + stream + '\'' + | |
| 88 | + ", ip='" + ip + '\'' + | |
| 89 | + ", params='" + params + '\'' + | |
| 90 | + ", port=" + port + | |
| 91 | + ", schema='" + schema + '\'' + | |
| 92 | + ", vhost='" + vhost + '\'' + | |
| 93 | + '}'; | |
| 85 | 94 | } |
| 86 | 95 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java
| ... | ... | @@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.service; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 4 | 4 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 5 | -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; | |
| 5 | +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; | |
| 6 | 6 | import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; |
| 7 | 7 | |
| 8 | 8 | import java.util.List; |
| ... | ... | @@ -38,7 +38,7 @@ public interface IDeviceChannelService { |
| 38 | 38 | * 获取统计信息 |
| 39 | 39 | * @return |
| 40 | 40 | */ |
| 41 | - ResourceBaceInfo getOverview(); | |
| 41 | + ResourceBaseInfo getOverview(); | |
| 42 | 42 | |
| 43 | 43 | /** |
| 44 | 44 | * 查询所有未分配的通道 | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
| ... | ... | @@ -5,7 +5,7 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 5 | 5 | import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; |
| 6 | 6 | import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; |
| 7 | 7 | import com.genersoft.iot.vmp.vmanager.bean.BaseTree; |
| 8 | -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; | |
| 8 | +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; | |
| 9 | 9 | |
| 10 | 10 | import java.util.List; |
| 11 | 11 | |
| ... | ... | @@ -162,7 +162,7 @@ public interface IDeviceService { |
| 162 | 162 | * 获取统计信息 |
| 163 | 163 | * @return |
| 164 | 164 | */ |
| 165 | - ResourceBaceInfo getOverview(); | |
| 165 | + ResourceBaseInfo getOverview(); | |
| 166 | 166 | |
| 167 | 167 | /** |
| 168 | 168 | * 获取所有设备 | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IInviteStreamService.java
| ... | ... | @@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.service; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.common.InviteInfo; |
| 4 | 4 | import com.genersoft.iot.vmp.common.InviteSessionType; |
| 5 | -import com.genersoft.iot.vmp.service.bean.InviteErrorCallback; | |
| 5 | +import com.genersoft.iot.vmp.service.bean.ErrorCallback; | |
| 6 | 6 | |
| 7 | 7 | /** |
| 8 | 8 | * 记录国标点播的状态,包括实时预览,下载,录像回放 |
| ... | ... | @@ -14,6 +14,8 @@ public interface IInviteStreamService { |
| 14 | 14 | */ |
| 15 | 15 | void updateInviteInfo(InviteInfo inviteInfo); |
| 16 | 16 | |
| 17 | + InviteInfo updateInviteInfoForStream(InviteInfo inviteInfo, String stream); | |
| 18 | + | |
| 17 | 19 | /** |
| 18 | 20 | * 获取点播的状态信息 |
| 19 | 21 | */ |
| ... | ... | @@ -54,7 +56,7 @@ public interface IInviteStreamService { |
| 54 | 56 | /** |
| 55 | 57 | * 添加一个invite回调 |
| 56 | 58 | */ |
| 57 | - void once(InviteSessionType type, String deviceId, String channelId, String stream, InviteErrorCallback<Object> callback); | |
| 59 | + void once(InviteSessionType type, String deviceId, String channelId, String stream, ErrorCallback<Object> callback); | |
| 58 | 60 | |
| 59 | 61 | /** |
| 60 | 62 | * 调用一个invite回调 |
| ... | ... | @@ -65,4 +67,12 @@ public interface IInviteStreamService { |
| 65 | 67 | * 清空一个设备的所有invite信息 |
| 66 | 68 | */ |
| 67 | 69 | void clearInviteInfo(String deviceId); |
| 70 | + | |
| 71 | + /** | |
| 72 | + * 统计同一个zlm下的国标收流个数 | |
| 73 | + */ | |
| 74 | + int getStreamInfoCount(String mediaServerId); | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 68 | 78 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
| ... | ... | @@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 7 | 7 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 8 | 8 | import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; |
| 9 | 9 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 10 | -import com.genersoft.iot.vmp.service.bean.InviteErrorCallback; | |
| 10 | +import com.genersoft.iot.vmp.service.bean.ErrorCallback; | |
| 11 | 11 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| 12 | 12 | import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; |
| 13 | 13 | import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent; |
| ... | ... | @@ -25,8 +25,8 @@ import java.util.Map; |
| 25 | 25 | public interface IPlayService { |
| 26 | 26 | |
| 27 | 27 | void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, |
| 28 | - InviteErrorCallback<Object> callback); | |
| 29 | - SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, InviteErrorCallback<Object> callback); | |
| 28 | + ErrorCallback<Object> callback); | |
| 29 | + SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, ErrorCallback<Object> callback); | |
| 30 | 30 | |
| 31 | 31 | StreamInfo onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId); |
| 32 | 32 | |
| ... | ... | @@ -37,13 +37,13 @@ public interface IPlayService { |
| 37 | 37 | */ |
| 38 | 38 | MediaServerItem getNewMediaServerItemHasAssist(Device device); |
| 39 | 39 | |
| 40 | - void playBack(String deviceId, String channelId, String startTime, String endTime, InviteErrorCallback<Object> callback); | |
| 41 | - void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, InviteErrorCallback<Object> callback); | |
| 40 | + void playBack(String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback); | |
| 41 | + void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback); | |
| 42 | 42 | |
| 43 | 43 | void zlmServerOffline(String mediaServerId); |
| 44 | 44 | |
| 45 | - void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback); | |
| 46 | - void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback); | |
| 45 | + void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback); | |
| 46 | + void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback); | |
| 47 | 47 | |
| 48 | 48 | StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream); |
| 49 | 49 | |
| ... | ... | @@ -69,4 +69,6 @@ public interface IPlayService { |
| 69 | 69 | void talkCmd(Device device, String channelId, MediaServerItem mediaServerItem, String stream, AudioBroadcastEvent event); |
| 70 | 70 | |
| 71 | 71 | void stopTalk(Device device, String channelId, Boolean streamIsReady); |
| 72 | + | |
| 73 | + void getSnap(String deviceId, String channelId, String fileName, ErrorCallback errorCallback); | |
| 72 | 74 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IRecordInfoServer.java deleted
100644 → 0
src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
| 1 | 1 | package com.genersoft.iot.vmp.service; |
| 2 | 2 | |
| 3 | 3 | import com.alibaba.fastjson2.JSONObject; |
| 4 | +import com.genersoft.iot.vmp.common.GeneralCallback; | |
| 4 | 5 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 5 | 6 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 6 | 7 | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; |
| 7 | -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; | |
| 8 | +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; | |
| 8 | 9 | import com.github.pagehelper.PageInfo; |
| 9 | 10 | |
| 10 | 11 | public interface IStreamProxyService { |
| ... | ... | @@ -13,7 +14,7 @@ public interface IStreamProxyService { |
| 13 | 14 | * 保存视频代理 |
| 14 | 15 | * @param param |
| 15 | 16 | */ |
| 16 | - StreamInfo save(StreamProxyItem param); | |
| 17 | + void save(StreamProxyItem param, GeneralCallback<StreamInfo> callback); | |
| 17 | 18 | |
| 18 | 19 | /** |
| 19 | 20 | * 添加视频代理到zlm |
| ... | ... | @@ -108,6 +109,6 @@ public interface IStreamProxyService { |
| 108 | 109 | * 获取统计信息 |
| 109 | 110 | * @return |
| 110 | 111 | */ |
| 111 | - ResourceBaceInfo getOverview(); | |
| 112 | + ResourceBaseInfo getOverview(); | |
| 112 | 113 | |
| 113 | 114 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
| ... | ... | @@ -5,7 +5,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; |
| 5 | 5 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 6 | 6 | import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; |
| 7 | 7 | import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; |
| 8 | -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; | |
| 8 | +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; | |
| 9 | 9 | import com.github.pagehelper.PageInfo; |
| 10 | 10 | |
| 11 | 11 | import java.util.List; |
| ... | ... | @@ -113,5 +113,5 @@ public interface IStreamPushService { |
| 113 | 113 | * 获取统计信息 |
| 114 | 114 | * @return |
| 115 | 115 | */ |
| 116 | - ResourceBaceInfo getOverview(); | |
| 116 | + ResourceBaseInfo getOverview(); | |
| 117 | 117 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCallback.java renamed to src/main/java/com/genersoft/iot/vmp/service/bean/ErrorCallback.java
src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCode.java
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
| ... | ... | @@ -11,7 +11,7 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 11 | 11 | import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; |
| 12 | 12 | import com.genersoft.iot.vmp.storager.dao.DeviceMapper; |
| 13 | 13 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 14 | -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; | |
| 14 | +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; | |
| 15 | 15 | import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; |
| 16 | 16 | import org.slf4j.Logger; |
| 17 | 17 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -50,8 +50,6 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { |
| 50 | 50 | device = deviceMapper.getDeviceByDeviceId(deviceChannel.getDeviceId()); |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | - | |
| 54 | - | |
| 55 | 53 | if ("WGS84".equals(device.getGeoCoordSys())) { |
| 56 | 54 | deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude()); |
| 57 | 55 | deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude()); |
| ... | ... | @@ -175,8 +173,12 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { |
| 175 | 173 | } |
| 176 | 174 | |
| 177 | 175 | @Override |
| 178 | - public ResourceBaceInfo getOverview() { | |
| 179 | - return channelMapper.getOverview(); | |
| 176 | + public ResourceBaseInfo getOverview() { | |
| 177 | + | |
| 178 | + int online = channelMapper.getOnlineCount(); | |
| 179 | + int total = channelMapper.getAllChannelCount(); | |
| 180 | + | |
| 181 | + return new ResourceBaseInfo(total, online); | |
| 180 | 182 | } |
| 181 | 183 | |
| 182 | 184 | |
| ... | ... | @@ -258,4 +260,6 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { |
| 258 | 260 | } |
| 259 | 261 | } |
| 260 | 262 | } |
| 263 | + | |
| 264 | + | |
| 261 | 265 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
| 1 | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | |
| 3 | +import com.genersoft.iot.vmp.common.InviteSessionType; | |
| 3 | 4 | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| 4 | 5 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 5 | 6 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 7 | +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; | |
| 6 | 8 | import com.genersoft.iot.vmp.gb28181.bean.*; |
| 7 | 9 | import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; |
| 8 | 10 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| ... | ... | @@ -10,6 +12,7 @@ import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; |
| 10 | 12 | import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask; |
| 11 | 13 | import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask; |
| 12 | 14 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| 15 | +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | |
| 13 | 16 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler; |
| 14 | 17 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| 15 | 18 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| ... | ... | @@ -23,7 +26,7 @@ import com.genersoft.iot.vmp.storager.dao.DeviceMapper; |
| 23 | 26 | import com.genersoft.iot.vmp.storager.dao.PlatformChannelMapper; |
| 24 | 27 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 25 | 28 | import com.genersoft.iot.vmp.vmanager.bean.BaseTree; |
| 26 | -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; | |
| 29 | +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; | |
| 27 | 30 | import org.slf4j.Logger; |
| 28 | 31 | import org.slf4j.LoggerFactory; |
| 29 | 32 | import org.springframework.beans.factory.annotation.Autowired; |
| ... | ... | @@ -49,6 +52,8 @@ public class DeviceServiceImpl implements IDeviceService { |
| 49 | 52 | private final static Logger logger = LoggerFactory.getLogger(DeviceServiceImpl.class); |
| 50 | 53 | |
| 51 | 54 | @Autowired |
| 55 | + private SIPCommander cmder; | |
| 56 | + @Autowired | |
| 52 | 57 | private DynamicTask dynamicTask; |
| 53 | 58 | |
| 54 | 59 | @Autowired |
| ... | ... | @@ -124,9 +129,10 @@ public class DeviceServiceImpl implements IDeviceService { |
| 124 | 129 | } |
| 125 | 130 | |
| 126 | 131 | // 第一次上线 或则设备之前是离线状态--进行通道同步和设备信息查询 |
| 127 | - if (device.getCreateTime() == null) { | |
| 128 | - device.setOnline(1); | |
| 132 | + if (deviceInDb == null) { | |
| 133 | + device.setOnLine(true); | |
| 129 | 134 | device.setCreateTime(now); |
| 135 | + device.setUpdateTime(now); | |
| 130 | 136 | logger.info("[设备上线,首次注册]: {},查询设备信息以及通道信息", device.getDeviceId()); |
| 131 | 137 | deviceMapper.add(device); |
| 132 | 138 | redisCatchStorage.updateDevice(device); |
| ... | ... | @@ -137,8 +143,12 @@ public class DeviceServiceImpl implements IDeviceService { |
| 137 | 143 | } |
| 138 | 144 | sync(device); |
| 139 | 145 | }else { |
| 140 | - if(device.getOnline() == 0){ | |
| 141 | - device.setOnline(1); | |
| 146 | + | |
| 147 | + if (deviceInDb != null) { | |
| 148 | + device.setSwitchPrimarySubStream(deviceInDb.isSwitchPrimarySubStream()); | |
| 149 | + } | |
| 150 | + if(!device.isOnLine()){ | |
| 151 | + device.setOnLine(true); | |
| 142 | 152 | device.setCreateTime(now); |
| 143 | 153 | deviceMapper.update(device); |
| 144 | 154 | redisCatchStorage.updateDevice(device); |
| ... | ... | @@ -185,14 +195,14 @@ public class DeviceServiceImpl implements IDeviceService { |
| 185 | 195 | |
| 186 | 196 | @Override |
| 187 | 197 | public void offline(String deviceId, String reason) { |
| 188 | - logger.error("[设备离线],{}, device:{}", reason, deviceId); | |
| 198 | + logger.warn("[设备离线],{}, device:{}", reason, deviceId); | |
| 189 | 199 | Device device = deviceMapper.getDeviceByDeviceId(deviceId); |
| 190 | 200 | if (device == null) { |
| 191 | 201 | return; |
| 192 | 202 | } |
| 193 | 203 | String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + deviceId; |
| 194 | 204 | dynamicTask.stop(registerExpireTaskKey); |
| 195 | - device.setOnline(0); | |
| 205 | + device.setOnLine(false); | |
| 196 | 206 | redisCatchStorage.updateDevice(device); |
| 197 | 207 | deviceMapper.update(device); |
| 198 | 208 | //进行通道离线 |
| ... | ... | @@ -256,7 +266,7 @@ public class DeviceServiceImpl implements IDeviceService { |
| 256 | 266 | } |
| 257 | 267 | logger.info("[移除目录订阅]: {}", device.getDeviceId()); |
| 258 | 268 | String taskKey = device.getDeviceId() + "catalog"; |
| 259 | - if (device.getOnline() == 1) { | |
| 269 | + if (device.isOnLine()) { | |
| 260 | 270 | Runnable runnable = dynamicTask.get(taskKey); |
| 261 | 271 | if (runnable instanceof ISubscribeTask) { |
| 262 | 272 | ISubscribeTask subscribeTask = (ISubscribeTask) runnable; |
| ... | ... | @@ -289,7 +299,7 @@ public class DeviceServiceImpl implements IDeviceService { |
| 289 | 299 | } |
| 290 | 300 | logger.info("[移除移动位置订阅]: {}", device.getDeviceId()); |
| 291 | 301 | String taskKey = device.getDeviceId() + "mobile_position"; |
| 292 | - if (device.getOnline() == 1) { | |
| 302 | + if (device.isOnLine()) { | |
| 293 | 303 | Runnable runnable = dynamicTask.get(taskKey); |
| 294 | 304 | if (runnable instanceof ISubscribeTask) { |
| 295 | 305 | ISubscribeTask subscribeTask = (ISubscribeTask) runnable; |
| ... | ... | @@ -356,7 +366,7 @@ public class DeviceServiceImpl implements IDeviceService { |
| 356 | 366 | |
| 357 | 367 | @Override |
| 358 | 368 | public void checkDeviceStatus(Device device) { |
| 359 | - if (device == null || device.getOnline() == 0) { | |
| 369 | + if (device == null || !device.isOnLine()) { | |
| 360 | 370 | return; |
| 361 | 371 | } |
| 362 | 372 | try { |
| ... | ... | @@ -405,63 +415,11 @@ public class DeviceServiceImpl implements IDeviceService { |
| 405 | 415 | if (device == null) { |
| 406 | 416 | return null; |
| 407 | 417 | } |
| 408 | - if (parentId == null || parentId.equals(deviceId)) { | |
| 409 | - // 字根节点开始查询 | |
| 410 | - List<DeviceChannel> rootNodes = getRootNodes(deviceId, TreeType.CIVIL_CODE.equals(device.getTreeType()), true, !onlyCatalog); | |
| 411 | - return transportChannelsToTree(rootNodes, ""); | |
| 412 | - } | |
| 413 | - | |
| 414 | - if (TreeType.CIVIL_CODE.equals(device.getTreeType())) { | |
| 415 | - if (parentId.length()%2 != 0) { | |
| 416 | - return null; | |
| 417 | - } | |
| 418 | - // 使用行政区划展示树 | |
| 419 | -// if (parentId.length() > 10) { | |
| 420 | -// // TODO 可能是行政区划与业务分组混杂的情形 | |
| 421 | -// return null; | |
| 422 | -// } | |
| 423 | - | |
| 424 | - if (parentId.length() == 10 ) { | |
| 425 | - if (onlyCatalog) { | |
| 426 | - return null; | |
| 427 | - } | |
| 428 | - // parentId为行业编码, 其下不会再有行政区划 | |
| 429 | - List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId); | |
| 430 | - List<BaseTree<DeviceChannel>> trees = transportChannelsToTree(channels, parentId); | |
| 431 | - return trees; | |
| 432 | - } | |
| 433 | - // 查询其下的行政区划和摄像机 | |
| 434 | - List<DeviceChannel> channelsForCivilCode = deviceChannelMapper.getChannelsWithCivilCodeAndLength(deviceId, parentId, parentId.length() + 2); | |
| 435 | - if (!onlyCatalog) { | |
| 436 | - List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId); | |
| 437 | - | |
| 438 | - for(DeviceChannel channel : channels) { | |
| 439 | - boolean flag = false; | |
| 440 | - for(DeviceChannel deviceChannel : channelsForCivilCode) { | |
| 441 | - if(channel.getChannelId().equals(deviceChannel.getChannelId())) { | |
| 442 | - flag = true; | |
| 443 | - } | |
| 444 | - } | |
| 445 | - if(!flag) { | |
| 446 | - channelsForCivilCode.add(channel); | |
| 447 | - } | |
| 448 | - } | |
| 449 | - } | |
| 450 | - List<BaseTree<DeviceChannel>> trees = transportChannelsToTree(channelsForCivilCode, parentId); | |
| 451 | - return trees; | |
| 452 | - | |
| 453 | - } | |
| 454 | - // 使用业务分组展示树 | |
| 455 | - if (TreeType.BUSINESS_GROUP.equals(device.getTreeType())) { | |
| 456 | - if (parentId.length() < 14 ) { | |
| 457 | - return null; | |
| 458 | - } | |
| 459 | - List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, parentId, null, null, null,null); | |
| 460 | - List<BaseTree<DeviceChannel>> trees = transportChannelsToTree(deviceChannels, parentId); | |
| 461 | - return trees; | |
| 418 | + if (ObjectUtils.isEmpty(parentId) || parentId.equals(deviceId)) { | |
| 419 | + parentId = null; | |
| 462 | 420 | } |
| 463 | - | |
| 464 | - return null; | |
| 421 | + List<DeviceChannel> rootNodes = deviceChannelMapper.getSubChannelsByDeviceId(deviceId, parentId, onlyCatalog); | |
| 422 | + return transportChannelsToTree(rootNodes, ""); | |
| 465 | 423 | } |
| 466 | 424 | |
| 467 | 425 | @Override |
| ... | ... | @@ -470,42 +428,11 @@ public class DeviceServiceImpl implements IDeviceService { |
| 470 | 428 | if (device == null) { |
| 471 | 429 | return null; |
| 472 | 430 | } |
| 473 | - if (parentId == null || parentId.equals(deviceId)) { | |
| 474 | - // 字根节点开始查询 | |
| 475 | - List<DeviceChannel> rootNodes = getRootNodes(deviceId, TreeType.CIVIL_CODE.equals(device.getTreeType()), false, true); | |
| 476 | - return rootNodes; | |
| 477 | - } | |
| 478 | - | |
| 479 | - if (TreeType.CIVIL_CODE.equals(device.getTreeType())) { | |
| 480 | - if (parentId.length()%2 != 0) { | |
| 481 | - return null; | |
| 482 | - } | |
| 483 | - // 使用行政区划展示树 | |
| 484 | - if (parentId.length() > 10) { | |
| 485 | - // TODO 可能是行政区划与业务分组混杂的情形 | |
| 486 | - return null; | |
| 487 | - } | |
| 488 | - | |
| 489 | - if (parentId.length() == 10 ) { | |
| 490 | - // parentId为行业编码, 其下不会再有行政区划 | |
| 491 | - List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId); | |
| 492 | - return channels; | |
| 493 | - } | |
| 494 | - // 查询其下的行政区划和摄像机 | |
| 495 | - List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId); | |
| 496 | - return channels; | |
| 497 | - | |
| 498 | - } | |
| 499 | - // 使用业务分组展示树 | |
| 500 | - if (TreeType.BUSINESS_GROUP.equals(device.getTreeType())) { | |
| 501 | - if (parentId.length() < 14 ) { | |
| 502 | - return null; | |
| 503 | - } | |
| 504 | - List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, parentId, null, null, null,null); | |
| 505 | - return deviceChannels; | |
| 431 | + if (ObjectUtils.isEmpty(parentId) || parentId.equals(deviceId)) { | |
| 432 | + return deviceChannelMapper.getSubChannelsByDeviceId(deviceId, null, false); | |
| 433 | + }else { | |
| 434 | + return deviceChannelMapper.getSubChannelsByDeviceId(deviceId, parentId, false); | |
| 506 | 435 | } |
| 507 | - | |
| 508 | - return null; | |
| 509 | 436 | } |
| 510 | 437 | |
| 511 | 438 | private List<BaseTree<DeviceChannel>> transportChannelsToTree(List<DeviceChannel> channels, String parentId) { |
| ... | ... | @@ -525,65 +452,26 @@ public class DeviceServiceImpl implements IDeviceService { |
| 525 | 452 | node.setPid(parentId); |
| 526 | 453 | node.setBasicData(channel); |
| 527 | 454 | node.setParent(false); |
| 528 | - if (channel.getChannelId().length() > 8) { | |
| 529 | - if (channel.getChannelId().length() > 13) { | |
| 530 | - String gbCodeType = channel.getChannelId().substring(10, 13); | |
| 531 | - node.setParent(gbCodeType.equals(ChannelIdType.BUSINESS_GROUP) || gbCodeType.equals(ChannelIdType.VIRTUAL_ORGANIZATION) ); | |
| 532 | - } | |
| 533 | - }else { | |
| 455 | + if (channel.getChannelId().length() <= 8) { | |
| 534 | 456 | node.setParent(true); |
| 535 | - } | |
| 536 | - treeNotes.add(node); | |
| 537 | - } | |
| 538 | - Collections.sort(treeNotes); | |
| 539 | - return treeNotes; | |
| 540 | - } | |
| 541 | - | |
| 542 | - private List<DeviceChannel> getRootNodes(String deviceId, boolean isCivilCode, boolean haveCatalog, boolean haveChannel) { | |
| 543 | - if (!haveCatalog && !haveChannel) { | |
| 544 | - return null; | |
| 545 | - } | |
| 546 | - List<DeviceChannel> result = new ArrayList<>(); | |
| 547 | - if (isCivilCode) { | |
| 548 | - // 使用行政区划 | |
| 549 | - Integer length= deviceChannelMapper.getChannelMinLength(deviceId); | |
| 550 | - if (length == null) { | |
| 551 | - return null; | |
| 552 | - } | |
| 553 | - if (length <= 10) { | |
| 554 | - if (haveCatalog) { | |
| 555 | - List<DeviceChannel> provinceNode = deviceChannelMapper.getChannelsWithCivilCodeAndLength(deviceId, null, length); | |
| 556 | - if (provinceNode != null && provinceNode.size() > 0) { | |
| 557 | - result.addAll(provinceNode); | |
| 558 | - } | |
| 559 | - } | |
| 560 | - | |
| 561 | - if (haveChannel) { | |
| 562 | - // 查询那些civilCode不在通道中的不规范通道,放置在根目录 | |
| 563 | - List<DeviceChannel> nonstandardNode = deviceChannelMapper.getChannelWithoutCiviCode(deviceId); | |
| 564 | - if (nonstandardNode != null && nonstandardNode.size() > 0) { | |
| 565 | - result.addAll(nonstandardNode); | |
| 566 | - } | |
| 567 | - } | |
| 568 | 457 | }else { |
| 569 | - if (haveChannel) { | |
| 570 | - List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, null, null, null, null,null); | |
| 571 | - if (deviceChannels != null && deviceChannels.size() > 0) { | |
| 572 | - result.addAll(deviceChannels); | |
| 458 | + if (channel.getChannelId().length() != 20) { | |
| 459 | + node.setParent(channel.getParental() == 1); | |
| 460 | + }else { | |
| 461 | + try { | |
| 462 | + int type = Integer.parseInt(channel.getChannelId().substring(10, 13)); | |
| 463 | + if (type == 215 || type == 216 || type == 200) { | |
| 464 | + node.setParent(true); | |
| 465 | + } | |
| 466 | + }catch (NumberFormatException e) { | |
| 467 | + node.setParent(false); | |
| 573 | 468 | } |
| 574 | 469 | } |
| 575 | 470 | } |
| 576 | - | |
| 577 | - }else { | |
| 578 | - // 使用业务分组+虚拟组织 | |
| 579 | - | |
| 580 | - // 只获取业务分组 | |
| 581 | - List<DeviceChannel> deviceChannels = deviceChannelMapper.getBusinessGroups(deviceId, ChannelIdType.BUSINESS_GROUP); | |
| 582 | - if (deviceChannels != null && deviceChannels.size() > 0) { | |
| 583 | - result.addAll(deviceChannels); | |
| 584 | - } | |
| 471 | + treeNotes.add(node); | |
| 585 | 472 | } |
| 586 | - return result; | |
| 473 | + Collections.sort(treeNotes); | |
| 474 | + return treeNotes; | |
| 587 | 475 | } |
| 588 | 476 | |
| 589 | 477 | @Override |
| ... | ... | @@ -593,7 +481,7 @@ public class DeviceServiceImpl implements IDeviceService { |
| 593 | 481 | |
| 594 | 482 | @Override |
| 595 | 483 | public void addDevice(Device device) { |
| 596 | - device.setOnline(0); | |
| 484 | + device.setOnLine(false); | |
| 597 | 485 | device.setCreateTime(DateUtil.getNow()); |
| 598 | 486 | device.setUpdateTime(DateUtil.getNow()); |
| 599 | 487 | deviceMapper.addCustomDevice(device); |
| ... | ... | @@ -606,6 +494,22 @@ public class DeviceServiceImpl implements IDeviceService { |
| 606 | 494 | logger.warn("更新设备时未找到设备信息"); |
| 607 | 495 | return; |
| 608 | 496 | } |
| 497 | + if(deviceInStore.isSwitchPrimarySubStream() != device.isSwitchPrimarySubStream()){ | |
| 498 | + //当修改设备的主子码流开关时,需要校验是否存在流,如果存在流则直接关闭 | |
| 499 | + List<SsrcTransaction> ssrcTransactionForAll = streamSession.getSsrcTransactionForAll(device.getDeviceId(), null, null, null); | |
| 500 | + if(ssrcTransactionForAll != null){ | |
| 501 | + for (SsrcTransaction ssrcTransaction: ssrcTransactionForAll) { | |
| 502 | + try { | |
| 503 | + cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), ssrcTransaction.getStream(), null, null); | |
| 504 | + } catch (InvalidArgumentException | SsrcTransactionNotFoundException | ParseException | SipException e) { | |
| 505 | + throw new RuntimeException(e); | |
| 506 | + } | |
| 507 | + } | |
| 508 | + } | |
| 509 | + deviceChannelMapper.clearPlay(device.getDeviceId()); | |
| 510 | + inviteStreamService.clearInviteInfo(device.getDeviceId()); | |
| 511 | + } | |
| 512 | + | |
| 609 | 513 | if (!ObjectUtils.isEmpty(device.getName())) { |
| 610 | 514 | deviceInStore.setName(device.getName()); |
| 611 | 515 | } |
| ... | ... | @@ -617,7 +521,6 @@ public class DeviceServiceImpl implements IDeviceService { |
| 617 | 521 | } |
| 618 | 522 | deviceInStore.setSdpIp(device.getSdpIp()); |
| 619 | 523 | deviceInStore.setCharset(device.getCharset()); |
| 620 | - deviceInStore.setTreeType(device.getTreeType()); | |
| 621 | 524 | |
| 622 | 525 | // 目录订阅相关的信息 |
| 623 | 526 | if (device.getSubscribeCycleForCatalog() > 0) { |
| ... | ... | @@ -673,12 +576,17 @@ public class DeviceServiceImpl implements IDeviceService { |
| 673 | 576 | }catch (Exception e) { |
| 674 | 577 | dataSourceTransactionManager.rollback(transactionStatus); |
| 675 | 578 | } |
| 579 | + if (result) { | |
| 580 | + redisCatchStorage.removeDevice(deviceId); | |
| 581 | + } | |
| 676 | 582 | return result; |
| 677 | 583 | } |
| 678 | 584 | |
| 679 | 585 | @Override |
| 680 | - public ResourceBaceInfo getOverview() { | |
| 681 | - return deviceMapper.getOverview(); | |
| 586 | + public ResourceBaseInfo getOverview() { | |
| 587 | + List<Device> onlineDevices = deviceMapper.getOnlineDevices(); | |
| 588 | + List<Device> all = deviceMapper.getAll(); | |
| 589 | + return new ResourceBaseInfo(all.size(), onlineDevices.size()); | |
| 682 | 590 | } |
| 683 | 591 | |
| 684 | 592 | @Override | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
| ... | ... | @@ -110,23 +110,18 @@ public class GbStreamServiceImpl implements IGbStreamService { |
| 110 | 110 | deviceChannel.setLatitude(gbStream.getLatitude()); |
| 111 | 111 | deviceChannel.setDeviceId(platform.getDeviceGBId()); |
| 112 | 112 | deviceChannel.setManufacture("wvp-pro"); |
| 113 | - deviceChannel.setStatus(gbStream.isStatus()?1:0); | |
| 113 | + deviceChannel.setStatus(gbStream.isStatus()); | |
| 114 | 114 | |
| 115 | 115 | deviceChannel.setRegisterWay(1); |
| 116 | - deviceChannel.setCivilCode(platform.getAdministrativeDivision()); | |
| 117 | - | |
| 118 | - if (platform.getTreeType().equals(TreeType.CIVIL_CODE)){ | |
| 119 | - deviceChannel.setCivilCode(catalogId); | |
| 120 | - }else if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)){ | |
| 121 | - PlatformCatalog catalog = catalogMapper.select(catalogId); | |
| 122 | - if (catalog == null) { | |
| 123 | - deviceChannel.setParentId(platform.getDeviceGBId()); | |
| 124 | - deviceChannel.setBusinessGroupId(null); | |
| 125 | - }else { | |
| 126 | - deviceChannel.setParentId(catalog.getId()); | |
| 127 | - deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId()); | |
| 128 | - } | |
| 129 | 116 | |
| 117 | + PlatformCatalog catalog = catalogMapper.select(catalogId); | |
| 118 | + if (catalog != null) { | |
| 119 | + deviceChannel.setCivilCode(catalog.getCivilCode()); | |
| 120 | + deviceChannel.setParentId(catalog.getParentId()); | |
| 121 | + deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId()); | |
| 122 | + }else { | |
| 123 | + deviceChannel.setCivilCode(platform.getAdministrativeDivision()); | |
| 124 | + deviceChannel.setParentId(platform.getDeviceGBId()); | |
| 130 | 125 | } |
| 131 | 126 | |
| 132 | 127 | deviceChannel.setModel("live"); |
| ... | ... | @@ -218,23 +213,17 @@ public class GbStreamServiceImpl implements IGbStreamService { |
| 218 | 213 | }else { |
| 219 | 214 | status = gbStreamMapper.selectStatusForPush(gbStream.getApp(), gbStream.getStream()); |
| 220 | 215 | } |
| 221 | - deviceChannel.setStatus((status != null && status )?1:0); | |
| 216 | + deviceChannel.setStatus(status != null && status); | |
| 222 | 217 | |
| 223 | 218 | deviceChannel.setRegisterWay(1); |
| 224 | - deviceChannel.setCivilCode(platform.getAdministrativeDivision()); | |
| 225 | - | |
| 226 | - if (platform.getTreeType().equals(TreeType.CIVIL_CODE)){ | |
| 227 | - deviceChannel.setCivilCode(catalogId); | |
| 228 | - }else if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)){ | |
| 229 | - PlatformCatalog catalog = catalogMapper.select(catalogId); | |
| 230 | - if (catalog == null) { | |
| 231 | - deviceChannel.setParentId(platform.getDeviceGBId()); | |
| 232 | - deviceChannel.setBusinessGroupId(null); | |
| 233 | - }else { | |
| 234 | - deviceChannel.setParentId(catalog.getId()); | |
| 235 | - deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId()); | |
| 236 | - } | |
| 237 | - | |
| 219 | + PlatformCatalog catalog = catalogMapper.select(catalogId); | |
| 220 | + if (catalog != null) { | |
| 221 | + deviceChannel.setCivilCode(catalog.getCivilCode()); | |
| 222 | + deviceChannel.setParentId(catalog.getParentId()); | |
| 223 | + deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId()); | |
| 224 | + }else { | |
| 225 | + deviceChannel.setCivilCode(platform.getAdministrativeDivision()); | |
| 226 | + deviceChannel.setParentId(platform.getDeviceGBId()); | |
| 238 | 227 | } |
| 239 | 228 | |
| 240 | 229 | deviceChannel.setModel("live"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java
| ... | ... | @@ -6,7 +6,7 @@ import com.genersoft.iot.vmp.common.InviteSessionStatus; |
| 6 | 6 | import com.genersoft.iot.vmp.common.InviteSessionType; |
| 7 | 7 | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| 8 | 8 | import com.genersoft.iot.vmp.service.IInviteStreamService; |
| 9 | -import com.genersoft.iot.vmp.service.bean.InviteErrorCallback; | |
| 9 | +import com.genersoft.iot.vmp.service.bean.ErrorCallback; | |
| 10 | 10 | import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
| 11 | 11 | import org.slf4j.Logger; |
| 12 | 12 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -24,7 +24,7 @@ public class InviteStreamServiceImpl implements IInviteStreamService { |
| 24 | 24 | |
| 25 | 25 | private final Logger logger = LoggerFactory.getLogger(InviteStreamServiceImpl.class); |
| 26 | 26 | |
| 27 | - private final Map<String, List<InviteErrorCallback<Object>>> inviteErrorCallbackMap = new ConcurrentHashMap<>(); | |
| 27 | + private final Map<String, List<ErrorCallback<Object>>> inviteErrorCallbackMap = new ConcurrentHashMap<>(); | |
| 28 | 28 | |
| 29 | 29 | @Autowired |
| 30 | 30 | private RedisTemplate<Object, Object> redisTemplate; |
| ... | ... | @@ -85,6 +85,24 @@ public class InviteStreamServiceImpl implements IInviteStreamService { |
| 85 | 85 | } |
| 86 | 86 | |
| 87 | 87 | @Override |
| 88 | + public InviteInfo updateInviteInfoForStream(InviteInfo inviteInfo, String stream) { | |
| 89 | + | |
| 90 | + InviteInfo inviteInfoInDb = getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream()); | |
| 91 | + if (inviteInfoInDb == null) { | |
| 92 | + return null; | |
| 93 | + } | |
| 94 | + removeInviteInfo(inviteInfoInDb); | |
| 95 | + String key = VideoManagerConstants.INVITE_PREFIX + | |
| 96 | + "_" + inviteInfo.getType() + | |
| 97 | + "_" + inviteInfo.getDeviceId() + | |
| 98 | + "_" + inviteInfo.getChannelId() + | |
| 99 | + "_" + stream; | |
| 100 | + inviteInfoInDb.setStream(stream); | |
| 101 | + redisTemplate.opsForValue().set(key, inviteInfoInDb); | |
| 102 | + return inviteInfoInDb; | |
| 103 | + } | |
| 104 | + | |
| 105 | + @Override | |
| 88 | 106 | public InviteInfo getInviteInfo(InviteSessionType type, String deviceId, String channelId, String stream) { |
| 89 | 107 | String key = VideoManagerConstants.INVITE_PREFIX + |
| 90 | 108 | "_" + (type != null ? type : "*") + |
| ... | ... | @@ -141,9 +159,9 @@ public class InviteStreamServiceImpl implements IInviteStreamService { |
| 141 | 159 | } |
| 142 | 160 | |
| 143 | 161 | @Override |
| 144 | - public void once(InviteSessionType type, String deviceId, String channelId, String stream, InviteErrorCallback<Object> callback) { | |
| 162 | + public void once(InviteSessionType type, String deviceId, String channelId, String stream, ErrorCallback<Object> callback) { | |
| 145 | 163 | String key = buildKey(type, deviceId, channelId, stream); |
| 146 | - List<InviteErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key); | |
| 164 | + List<ErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key); | |
| 147 | 165 | if (callbacks == null) { |
| 148 | 166 | callbacks = new CopyOnWriteArrayList<>(); |
| 149 | 167 | inviteErrorCallbackMap.put(key, callbacks); |
| ... | ... | @@ -152,31 +170,60 @@ public class InviteStreamServiceImpl implements IInviteStreamService { |
| 152 | 170 | |
| 153 | 171 | } |
| 154 | 172 | |
| 173 | + private String buildKey(InviteSessionType type, String deviceId, String channelId, String stream) { | |
| 174 | + String key = type + "_" + deviceId + "_" + channelId; | |
| 175 | + // 如果ssrc未null那么可以实现一个通道只能一次操作,ssrc不为null则可以支持一个通道多次invite | |
| 176 | + if (stream != null) { | |
| 177 | + key += ("_" + stream); | |
| 178 | + } | |
| 179 | + return key; | |
| 180 | + } | |
| 181 | + | |
| 182 | + | |
| 183 | + @Override | |
| 184 | + public void clearInviteInfo(String deviceId) { | |
| 185 | + removeInviteInfo(null, deviceId, null, null); | |
| 186 | + } | |
| 187 | + | |
| 188 | + @Override | |
| 189 | + public int getStreamInfoCount(String mediaServerId) { | |
| 190 | + int count = 0; | |
| 191 | + String key = VideoManagerConstants.INVITE_PREFIX + "_*_*_*_*"; | |
| 192 | + List<Object> scanResult = RedisUtil.scan(redisTemplate, key); | |
| 193 | + if (scanResult.size() == 0) { | |
| 194 | + return 0; | |
| 195 | + }else { | |
| 196 | + for (Object keyObj : scanResult) { | |
| 197 | + String keyStr = (String) keyObj; | |
| 198 | + InviteInfo inviteInfo = (InviteInfo) redisTemplate.opsForValue().get(keyStr); | |
| 199 | + if (inviteInfo != null && inviteInfo.getStreamInfo() != null && inviteInfo.getStreamInfo().getMediaServerId().equals(mediaServerId)) { | |
| 200 | + count++; | |
| 201 | + } | |
| 202 | + } | |
| 203 | + } | |
| 204 | + return count; | |
| 205 | + } | |
| 206 | + | |
| 155 | 207 | @Override |
| 156 | 208 | public void call(InviteSessionType type, String deviceId, String channelId, String stream, int code, String msg, Object data) { |
| 157 | - String key = buildKey(type, deviceId, channelId, stream); | |
| 158 | - List<InviteErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key); | |
| 209 | + String key = buildSubStreamKey(type, deviceId, channelId, stream); | |
| 210 | + List<ErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key); | |
| 159 | 211 | if (callbacks == null) { |
| 160 | 212 | return; |
| 161 | 213 | } |
| 162 | - for (InviteErrorCallback<Object> callback : callbacks) { | |
| 214 | + for (ErrorCallback<Object> callback : callbacks) { | |
| 163 | 215 | callback.run(code, msg, data); |
| 164 | 216 | } |
| 165 | 217 | inviteErrorCallbackMap.remove(key); |
| 166 | 218 | } |
| 167 | 219 | |
| 168 | - private String buildKey(InviteSessionType type, String deviceId, String channelId, String stream) { | |
| 169 | - String key = type + "_" + deviceId + "_" + channelId; | |
| 170 | - // 如果ssrc未null那么可以实现一个通道只能一次操作,ssrc不为null则可以支持一个通道多次invite | |
| 220 | + | |
| 221 | + private String buildSubStreamKey(InviteSessionType type, String deviceId, String channelId, String stream) { | |
| 222 | + String key = type + "_" + "_" + deviceId + "_" + channelId; | |
| 223 | + // 如果ssrc为null那么可以实现一个通道只能一次操作,ssrc不为null则可以支持一个通道多次invite | |
| 171 | 224 | if (stream != null) { |
| 172 | 225 | key += ("_" + stream); |
| 173 | 226 | } |
| 174 | 227 | return key; |
| 175 | 228 | } |
| 176 | - | |
| 177 | - | |
| 178 | - @Override | |
| 179 | - public void clearInviteInfo(String deviceId) { | |
| 180 | - removeInviteInfo(null, deviceId, null, null); | |
| 181 | - } | |
| 182 | 229 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
| ... | ... | @@ -17,6 +17,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; |
| 17 | 17 | import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; |
| 18 | 18 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 19 | 19 | import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData; |
| 20 | +import com.genersoft.iot.vmp.service.IInviteStreamService; | |
| 20 | 21 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 21 | 22 | import com.genersoft.iot.vmp.service.bean.MediaServerLoad; |
| 22 | 23 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| ... | ... | @@ -98,6 +99,9 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 98 | 99 | private IRedisCatchStorage redisCatchStorage; |
| 99 | 100 | |
| 100 | 101 | @Autowired |
| 102 | + private IInviteStreamService inviteStreamService; | |
| 103 | + | |
| 104 | + @Autowired | |
| 101 | 105 | private RedisTemplate<Object, Object> redisTemplate; |
| 102 | 106 | |
| 103 | 107 | |
| ... | ... | @@ -423,7 +427,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 423 | 427 | } |
| 424 | 428 | final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + serverItem.getId(); |
| 425 | 429 | dynamicTask.stop(zlmKeepaliveKey); |
| 426 | - dynamicTask.startDelay(zlmKeepaliveKey, new KeepAliveTimeoutRunnable(serverItem), (Math.getExponent(serverItem.getHookAliveInterval()) + 5) * 1000); | |
| 430 | + dynamicTask.startDelay(zlmKeepaliveKey, new KeepAliveTimeoutRunnable(serverItem), (serverItem.getHookAliveInterval().intValue() + 5) * 1000); | |
| 427 | 431 | publisher.zlmOnlineEventPublish(serverItem.getId()); |
| 428 | 432 | |
| 429 | 433 | logger.info("[ZLM] 连接成功 {} - {}:{} ", |
| ... | ... | @@ -694,7 +698,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 694 | 698 | // 缓存不存在,从数据库查询,如果数据库不存在则是错误的 |
| 695 | 699 | mediaServerItem = getOneFromDatabase(mediaServerId); |
| 696 | 700 | if (mediaServerItem == null) { |
| 697 | - logger.warn("[更新ZLM 保活信息]失败,未找到流媒体信息"); | |
| 701 | + logger.warn("[更新ZLM 保活信息] 流媒体{}尚未加入使用,请检查节点中是否含有此流媒体 ", mediaServerId); | |
| 698 | 702 | return; |
| 699 | 703 | } |
| 700 | 704 | // zlm连接重试 |
| ... | ... | @@ -744,7 +748,8 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 744 | 748 | result.setId(mediaServerItem.getId()); |
| 745 | 749 | result.setPush(redisCatchStorage.getPushStreamCount(mediaServerItem.getId())); |
| 746 | 750 | result.setProxy(redisCatchStorage.getProxyStreamCount(mediaServerItem.getId())); |
| 747 | - result.setGbReceive(redisCatchStorage.getGbReceiveCount(mediaServerItem.getId())); | |
| 751 | + | |
| 752 | + result.setGbReceive(inviteStreamService.getStreamInfoCount(mediaServerItem.getId())); | |
| 748 | 753 | result.setGbSend(redisCatchStorage.getGbSendCount(mediaServerItem.getId())); |
| 749 | 754 | return result; |
| 750 | 755 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java
| ... | ... | @@ -126,22 +126,17 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { |
| 126 | 126 | List<DeviceChannel> deviceChannelList = new ArrayList<>(); |
| 127 | 127 | if (channelReduces.size() > 0){ |
| 128 | 128 | PlatformCatalog catalog = catalogManager.select(catalogId); |
| 129 | - if (catalog == null && !catalogId.equals(platform.getDeviceGBId())) { | |
| 129 | + if (catalog == null || !catalogId.equals(platform.getDeviceGBId())) { | |
| 130 | 130 | logger.warn("未查询到目录{}的信息", catalogId); |
| 131 | 131 | return null; |
| 132 | 132 | } |
| 133 | 133 | for (ChannelReduce channelReduce : channelReduces) { |
| 134 | 134 | DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); |
| 135 | 135 | deviceChannel.setParental(0); |
| 136 | + deviceChannel.setCivilCode(catalog.getCivilCode()); | |
| 137 | + deviceChannel.setParentId(catalog.getParentId()); | |
| 138 | + deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId()); | |
| 136 | 139 | deviceChannelList.add(deviceChannel); |
| 137 | - if (platform.getTreeType().equals(TreeType.CIVIL_CODE)){ | |
| 138 | - deviceChannel.setCivilCode(catalogId); | |
| 139 | - }else if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)){ | |
| 140 | - deviceChannel.setParentId(catalogId); | |
| 141 | - if (catalog != null) { | |
| 142 | - deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId()); | |
| 143 | - } | |
| 144 | - } | |
| 145 | 140 | } |
| 146 | 141 | } |
| 147 | 142 | return deviceChannelList; | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
| ... | ... | @@ -49,6 +49,8 @@ import java.util.UUID; |
| 49 | 49 | public class PlatformServiceImpl implements IPlatformService { |
| 50 | 50 | |
| 51 | 51 | private final static String REGISTER_KEY_PREFIX = "platform_register_"; |
| 52 | + | |
| 53 | + private final static String REGISTER_FAIL_AGAIN_KEY_PREFIX = "platform_register_fail_again_"; | |
| 52 | 54 | private final static String KEEPALIVE_KEY_PREFIX = "platform_keepalive_"; |
| 53 | 55 | |
| 54 | 56 | private final static Logger logger = LoggerFactory.getLogger(PlatformServiceImpl.class); |
| ... | ... | @@ -158,14 +160,6 @@ public class PlatformServiceImpl implements IPlatformService { |
| 158 | 160 | ParentPlatform parentPlatformOld = platformMapper.getParentPlatById(parentPlatform.getId()); |
| 159 | 161 | ParentPlatformCatch parentPlatformCatchOld = redisCatchStorage.queryPlatformCatchInfo(parentPlatformOld.getServerGBId()); |
| 160 | 162 | parentPlatform.setUpdateTime(DateUtil.getNow()); |
| 161 | - if (!parentPlatformOld.getTreeType().equals(parentPlatform.getTreeType())) { | |
| 162 | - // 目录结构发生变化,清空之前的关联关系 | |
| 163 | - logger.info("保存平台{}时发现目录结构变化,清空关联关系", parentPlatform.getDeviceGBId()); | |
| 164 | - catalogMapper.delByPlatformId(parentPlatformOld.getServerGBId()); | |
| 165 | - platformChannelMapper.delByPlatformId(parentPlatformOld.getServerGBId()); | |
| 166 | - platformGbStreamMapper.delByPlatformId(parentPlatformOld.getServerGBId()); | |
| 167 | - } | |
| 168 | - | |
| 169 | 163 | |
| 170 | 164 | // 停止心跳定时 |
| 171 | 165 | final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatformOld.getServerGBId(); |
| ... | ... | @@ -176,12 +170,11 @@ public class PlatformServiceImpl implements IPlatformService { |
| 176 | 170 | // 注销旧的 |
| 177 | 171 | try { |
| 178 | 172 | if (parentPlatformOld.isStatus()) { |
| 179 | - logger.info("保存平台{}时发现救平台在线,发送注销命令", parentPlatformOld.getServerGBId()); | |
| 173 | + logger.info("保存平台{}时发现旧平台在线,发送注销命令", parentPlatformOld.getServerGBId()); | |
| 180 | 174 | commanderForPlatform.unregister(parentPlatformOld, parentPlatformCatchOld.getSipTransactionInfo(), null, eventResult -> { |
| 181 | 175 | logger.info("[国标级联] 注销成功, 平台:{}", parentPlatformOld.getServerGBId()); |
| 182 | 176 | }); |
| 183 | 177 | } |
| 184 | - | |
| 185 | 178 | } catch (InvalidArgumentException | ParseException | SipException e) { |
| 186 | 179 | logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage()); |
| 187 | 180 | } |
| ... | ... | @@ -214,9 +207,6 @@ public class PlatformServiceImpl implements IPlatformService { |
| 214 | 207 | logger.error("[命令发送失败] 国标级联: {}", e.getMessage()); |
| 215 | 208 | } |
| 216 | 209 | } |
| 217 | - // 重新开启定时注册, 使用续订消息 | |
| 218 | - // 重新开始心跳保活 | |
| 219 | - | |
| 220 | 210 | |
| 221 | 211 | return false; |
| 222 | 212 | } |
| ... | ... | @@ -225,6 +215,9 @@ public class PlatformServiceImpl implements IPlatformService { |
| 225 | 215 | @Override |
| 226 | 216 | public void online(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo) { |
| 227 | 217 | logger.info("[国标级联]:{}, 平台上线", parentPlatform.getServerGBId()); |
| 218 | + final String registerFailAgainTaskKey = REGISTER_FAIL_AGAIN_KEY_PREFIX + parentPlatform.getServerGBId(); | |
| 219 | + dynamicTask.stop(registerFailAgainTaskKey); | |
| 220 | + | |
| 228 | 221 | platformMapper.updateParentPlatformStatus(parentPlatform.getServerGBId(), true); |
| 229 | 222 | ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); |
| 230 | 223 | if (parentPlatformCatch == null) { |
| ... | ... | @@ -265,15 +258,9 @@ public class PlatformServiceImpl implements IPlatformService { |
| 265 | 258 | // 此时是第三次心跳超时, 平台离线 |
| 266 | 259 | if (platformCatch.getKeepAliveReply() == 2) { |
| 267 | 260 | // 设置平台离线,并重新注册 |
| 268 | - logger.info("[国标级联] {},三次心跳超时后再次发起注册", parentPlatform.getServerGBId()); | |
| 269 | - try { | |
| 270 | - commanderForPlatform.register(parentPlatform, eventResult1 -> { | |
| 271 | - logger.info("[国标级联] {},三次心跳超时后再次发起注册仍然失败,开始定时发起注册,间隔为1分钟", parentPlatform.getServerGBId()); | |
| 272 | - offline(parentPlatform, false); | |
| 273 | - }, null); | |
| 274 | - } catch (InvalidArgumentException | ParseException | SipException e) { | |
| 275 | - logger.error("[命令发送失败] 国标级联 注册: {}", e.getMessage()); | |
| 276 | - } | |
| 261 | + logger.info("[国标级联] 三次心跳超时, 平台{}({})离线", parentPlatform.getName(), parentPlatform.getServerGBId()); | |
| 262 | + offline(parentPlatform, false); | |
| 263 | + | |
| 277 | 264 | } |
| 278 | 265 | |
| 279 | 266 | }else { |
| ... | ... | @@ -299,21 +286,22 @@ public class PlatformServiceImpl implements IPlatformService { |
| 299 | 286 | |
| 300 | 287 | private void registerTask(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo){ |
| 301 | 288 | try { |
| 302 | - // 设置超时重发, 后续从底层支持消息重发 | |
| 303 | - String key = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId() + "_timeout"; | |
| 304 | - if (dynamicTask.isAlive(key)) { | |
| 305 | - return; | |
| 289 | + // 不在同一个会话中续订则每次全新注册 | |
| 290 | + if (!userSetting.isRegisterKeepIntDialog()) { | |
| 291 | + sipTransactionInfo = null; | |
| 292 | + } | |
| 293 | + | |
| 294 | + if (sipTransactionInfo == null) { | |
| 295 | + logger.info("[国标级联] 平台:{}注册即将到期,开始重新注册", parentPlatform.getServerGBId()); | |
| 296 | + }else { | |
| 297 | + logger.info("[国标级联] 平台:{}注册即将到期,开始续订", parentPlatform.getServerGBId()); | |
| 306 | 298 | } |
| 307 | - dynamicTask.startDelay(key, ()->{ | |
| 308 | - registerTask(parentPlatform, sipTransactionInfo); | |
| 309 | - }, 1000); | |
| 310 | - logger.info("[国标级联] 平台:{}注册即将到期,开始续订", parentPlatform.getServerGBId()); | |
| 299 | + | |
| 311 | 300 | commanderForPlatform.register(parentPlatform, sipTransactionInfo, eventResult -> { |
| 312 | - dynamicTask.stop(key); | |
| 301 | + logger.info("[国标级联] 平台:{}注册失败,{}:{}", parentPlatform.getServerGBId(), | |
| 302 | + eventResult.statusCode, eventResult.msg); | |
| 313 | 303 | offline(parentPlatform, false); |
| 314 | - },eventResult -> { | |
| 315 | - dynamicTask.stop(key); | |
| 316 | - }); | |
| 304 | + }, null); | |
| 317 | 305 | } catch (InvalidArgumentException | ParseException | SipException e) { |
| 318 | 306 | logger.error("[命令发送失败] 国标级联定时注册: {}", e.getMessage()); |
| 319 | 307 | } |
| ... | ... | @@ -334,24 +322,35 @@ public class PlatformServiceImpl implements IPlatformService { |
| 334 | 322 | // 停止所有推流 |
| 335 | 323 | logger.info("[平台离线] {}, 停止所有推流", parentPlatform.getServerGBId()); |
| 336 | 324 | stopAllPush(parentPlatform.getServerGBId()); |
| 337 | - if (stopRegister) { | |
| 338 | - // 清除注册定时 | |
| 339 | - logger.info("[平台离线] {}, 停止定时注册任务", parentPlatform.getServerGBId()); | |
| 340 | - final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId(); | |
| 341 | - if (dynamicTask.contains(registerTaskKey)) { | |
| 342 | - dynamicTask.stop(registerTaskKey); | |
| 343 | - } | |
| 325 | + | |
| 326 | + // 清除注册定时 | |
| 327 | + logger.info("[平台离线] {}, 停止定时注册任务", parentPlatform.getServerGBId()); | |
| 328 | + final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId(); | |
| 329 | + if (dynamicTask.contains(registerTaskKey)) { | |
| 330 | + dynamicTask.stop(registerTaskKey); | |
| 344 | 331 | } |
| 345 | 332 | // 清除心跳定时 |
| 346 | 333 | logger.info("[平台离线] {}, 停止定时发送心跳任务", parentPlatform.getServerGBId()); |
| 347 | 334 | final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId(); |
| 348 | 335 | if (dynamicTask.contains(keepaliveTaskKey)) { |
| 349 | - // 添加心跳任务 | |
| 336 | + // 清除心跳任务 | |
| 350 | 337 | dynamicTask.stop(keepaliveTaskKey); |
| 351 | 338 | } |
| 352 | 339 | // 停止目录订阅回复 |
| 353 | 340 | logger.info("[平台离线] {}, 停止订阅回复", parentPlatform.getServerGBId()); |
| 354 | 341 | subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId()); |
| 342 | + // 发起定时自动重新注册 | |
| 343 | + if (!stopRegister) { | |
| 344 | + // 设置为60秒自动尝试重新注册 | |
| 345 | + final String registerFailAgainTaskKey = REGISTER_FAIL_AGAIN_KEY_PREFIX + parentPlatform.getServerGBId(); | |
| 346 | + ParentPlatform platform = platformMapper.getParentPlatById(parentPlatform.getId()); | |
| 347 | + if (platform.isEnable()) { | |
| 348 | + dynamicTask.startCron(registerFailAgainTaskKey, | |
| 349 | + ()-> registerTask(platform, null), | |
| 350 | + userSetting.getRegisterAgainAfterTime() * 1000); | |
| 351 | + } | |
| 352 | + | |
| 353 | + } | |
| 355 | 354 | } |
| 356 | 355 | |
| 357 | 356 | private void stopAllPush(String platformId) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
| 1 | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | |
| 3 | -import com.alibaba.fastjson2.JSONArray; | |
| 4 | 3 | import com.alibaba.fastjson2.JSONObject; |
| 5 | 4 | import com.genersoft.iot.vmp.common.InviteInfo; |
| 6 | 5 | import com.genersoft.iot.vmp.common.InviteSessionStatus; |
| ... | ... | @@ -29,8 +28,10 @@ import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; |
| 29 | 28 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout; |
| 30 | 29 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; |
| 31 | 30 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 31 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; | |
| 32 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; | |
| 32 | 33 | import com.genersoft.iot.vmp.service.*; |
| 33 | -import com.genersoft.iot.vmp.service.bean.InviteErrorCallback; | |
| 34 | +import com.genersoft.iot.vmp.service.bean.ErrorCallback; | |
| 34 | 35 | import com.genersoft.iot.vmp.service.bean.InviteErrorCode; |
| 35 | 36 | import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg; |
| 36 | 37 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| ... | ... | @@ -57,6 +58,7 @@ import javax.sip.InvalidArgumentException; |
| 57 | 58 | import javax.sip.ResponseEvent; |
| 58 | 59 | import javax.sip.SipException; |
| 59 | 60 | import javax.sip.header.CallIdHeader; |
| 61 | +import java.io.File; | |
| 60 | 62 | import java.math.BigDecimal; |
| 61 | 63 | import java.math.RoundingMode; |
| 62 | 64 | import java.text.ParseException; |
| ... | ... | @@ -144,14 +146,13 @@ public class PlayServiceImpl implements IPlayService { |
| 144 | 146 | |
| 145 | 147 | |
| 146 | 148 | @Override |
| 147 | - public SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, InviteErrorCallback<Object> callback) { | |
| 149 | + public SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, ErrorCallback<Object> callback) { | |
| 148 | 150 | if (mediaServerItem == null) { |
| 149 | 151 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm"); |
| 150 | 152 | } |
| 151 | 153 | |
| 152 | 154 | Device device = redisCatchStorage.getDevice(deviceId); |
| 153 | 155 | InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId); |
| 154 | - | |
| 155 | 156 | if (inviteInfo != null ) { |
| 156 | 157 | if (inviteInfo.getStreamInfo() == null) { |
| 157 | 158 | // 点播发起了但是尚未成功, 仅注册回调等待结果即可 |
| ... | ... | @@ -353,7 +354,7 @@ public class PlayServiceImpl implements IPlayService { |
| 353 | 354 | |
| 354 | 355 | @Override |
| 355 | 356 | public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, |
| 356 | - InviteErrorCallback<Object> callback) { | |
| 357 | + ErrorCallback<Object> callback) { | |
| 357 | 358 | |
| 358 | 359 | if (mediaServerItem == null || ssrcInfo == null) { |
| 359 | 360 | callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(), |
| ... | ... | @@ -361,8 +362,9 @@ public class PlayServiceImpl implements IPlayService { |
| 361 | 362 | null); |
| 362 | 363 | return; |
| 363 | 364 | } |
| 364 | - logger.info("[点播开始] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); | |
| 365 | - | |
| 365 | + logger.info("[点播开始] deviceId: {}, channelId: {},码流类型:{},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}", | |
| 366 | + device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流", ssrcInfo.getPort(), | |
| 367 | + device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); | |
| 366 | 368 | //端口获取失败的ssrcInfo 没有必要发送点播指令 |
| 367 | 369 | if (ssrcInfo.getPort() <= 0) { |
| 368 | 370 | logger.info("[点播端口分配异常],deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channelId, ssrcInfo); |
| ... | ... | @@ -377,9 +379,10 @@ public class PlayServiceImpl implements IPlayService { |
| 377 | 379 | } |
| 378 | 380 | |
| 379 | 381 | // 初始化redis中的invite消息状态 |
| 380 | - InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo, | |
| 382 | + InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo, | |
| 381 | 383 | mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAY, |
| 382 | 384 | InviteSessionStatus.ready); |
| 385 | + inviteInfo.setSubStream(device.isSwitchPrimarySubStream()); | |
| 383 | 386 | inviteStreamService.updateInviteInfo(inviteInfo); |
| 384 | 387 | // 超时处理 |
| 385 | 388 | String timeOutTaskKey = UUID.randomUUID().toString(); |
| ... | ... | @@ -387,7 +390,10 @@ public class PlayServiceImpl implements IPlayService { |
| 387 | 390 | // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况 |
| 388 | 391 | InviteInfo inviteInfoForTimeOut = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId); |
| 389 | 392 | if (inviteInfoForTimeOut == null || inviteInfoForTimeOut.getStreamInfo() == null) { |
| 390 | - logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", device.getDeviceId(), channelId, ssrcInfo.getPort(), ssrcInfo.getSsrc()); | |
| 393 | + logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},码流类型:{},端口:{}, SSRC: {}", | |
| 394 | + device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流", | |
| 395 | + ssrcInfo.getPort(), ssrcInfo.getSsrc()); | |
| 396 | + | |
| 391 | 397 | // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 |
| 392 | 398 | // InviteInfo inviteInfoForTimeout = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.play, device.getDeviceId(), channelId); |
| 393 | 399 | // if (inviteInfoForTimeout == null) { |
| ... | ... | @@ -401,8 +407,8 @@ public class PlayServiceImpl implements IPlayService { |
| 401 | 407 | callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null); |
| 402 | 408 | inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null, |
| 403 | 409 | InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null); |
| 404 | - | |
| 405 | 410 | inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId); |
| 411 | + | |
| 406 | 412 | try { |
| 407 | 413 | cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null); |
| 408 | 414 | } catch (InvalidArgumentException | ParseException | SipException | |
| ... | ... | @@ -421,11 +427,11 @@ public class PlayServiceImpl implements IPlayService { |
| 421 | 427 | }, userSetting.getPlayTimeout()); |
| 422 | 428 | |
| 423 | 429 | try { |
| 424 | - cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> { | |
| 425 | - logger.info("收到订阅消息: " + response.toJSONString()); | |
| 430 | + cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInuse, hookParam ) -> { | |
| 431 | + logger.info("收到订阅消息: " + hookParam); | |
| 426 | 432 | dynamicTask.stop(timeOutTaskKey); |
| 427 | 433 | // hook响应 |
| 428 | - StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId); | |
| 434 | + StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInuse, hookParam, device.getDeviceId(), channelId); | |
| 429 | 435 | if (streamInfo == null){ |
| 430 | 436 | callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(), |
| 431 | 437 | InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null); |
| ... | ... | @@ -439,7 +445,8 @@ public class PlayServiceImpl implements IPlayService { |
| 439 | 445 | InviteErrorCode.SUCCESS.getCode(), |
| 440 | 446 | InviteErrorCode.SUCCESS.getMsg(), |
| 441 | 447 | streamInfo); |
| 442 | - logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId); | |
| 448 | + logger.info("[点播成功] deviceId: {}, channelId: {},码流类型:{}", device.getDeviceId(), | |
| 449 | + device.isSwitchPrimarySubStream() ? "辅码流" : "主码流"); | |
| 443 | 450 | String streamUrl; |
| 444 | 451 | if (mediaServerItemInuse.getRtspPort() != 0) { |
| 445 | 452 | streamUrl = String.format("rtsp://127.0.0.1:%s/%s/%s", mediaServerItemInuse.getRtspPort(), "rtp", ssrcInfo.getStream()); |
| ... | ... | @@ -505,21 +512,8 @@ public class PlayServiceImpl implements IPlayService { |
| 505 | 512 | logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse); |
| 506 | 513 | if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) { |
| 507 | 514 | logger.info("[点播消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); |
| 508 | - if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) { | |
| 509 | - // ssrc 不可用 | |
| 510 | - logger.info("[点播消息] SSRC修正时发现ssrc不可使用 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); | |
| 511 | - // 释放ssrc | |
| 512 | - ssrcFactory.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 513 | - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 514 | - | |
| 515 | - callback.run(InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(), | |
| 516 | - InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null); | |
| 517 | - inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null, | |
| 518 | - InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(), | |
| 519 | - InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null); | |
| 520 | - | |
| 521 | - return; | |
| 522 | - } | |
| 515 | + // 释放ssrc | |
| 516 | + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 523 | 517 | // 单端口模式streamId也有变化,重新设置监听即可 |
| 524 | 518 | if (!mediaServerItem.isRtpEnable()) { |
| 525 | 519 | // 添加订阅 |
| ... | ... | @@ -527,12 +521,12 @@ public class PlayServiceImpl implements IPlayService { |
| 527 | 521 | subscribe.removeSubscribe(hookSubscribe); |
| 528 | 522 | String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase(); |
| 529 | 523 | hookSubscribe.getContent().put("stream", stream); |
| 530 | - inviteInfo.setStream(stream); | |
| 531 | - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> { | |
| 532 | - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString()); | |
| 524 | + inviteStreamService.updateInviteInfoForStream(inviteInfo, stream); | |
| 525 | + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> { | |
| 526 | + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam); | |
| 533 | 527 | dynamicTask.stop(timeOutTaskKey); |
| 534 | 528 | // hook响应 |
| 535 | - StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId); | |
| 529 | + StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInUse, hookParam, device.getDeviceId(), channelId); | |
| 536 | 530 | if (streamInfo == null){ |
| 537 | 531 | callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(), |
| 538 | 532 | InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null); |
| ... | ... | @@ -542,7 +536,7 @@ public class PlayServiceImpl implements IPlayService { |
| 542 | 536 | return; |
| 543 | 537 | } |
| 544 | 538 | callback.run(InviteErrorCode.SUCCESS.getCode(), |
| 545 | - InviteErrorCode.SUCCESS.getMsg(), null); | |
| 539 | + InviteErrorCode.SUCCESS.getMsg(), streamInfo); | |
| 546 | 540 | inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null, |
| 547 | 541 | InviteErrorCode.SUCCESS.getCode(), |
| 548 | 542 | InviteErrorCode.SUCCESS.getMsg(), |
| ... | ... | @@ -574,6 +568,9 @@ public class PlayServiceImpl implements IPlayService { |
| 574 | 568 | "下级自定义了ssrc,重新设置收流信息失败", null); |
| 575 | 569 | |
| 576 | 570 | }else { |
| 571 | + if (ssrcInfo.getStream()!= null && !ssrcInfo.getStream().equals(inviteInfo.getStream())) { | |
| 572 | + inviteStreamService.removeInviteInfo(inviteInfo); | |
| 573 | + } | |
| 577 | 574 | ssrcInfo.setSsrc(ssrcInResponse); |
| 578 | 575 | inviteInfo.setSsrcInfo(ssrcInfo); |
| 579 | 576 | inviteInfo.setStream(ssrcInfo.getStream()); |
| ... | ... | @@ -622,6 +619,8 @@ public class PlayServiceImpl implements IPlayService { |
| 622 | 619 | @Override |
| 623 | 620 | public StreamInfo onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId) { |
| 624 | 621 | StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); |
| 622 | + Device device = redisCatchStorage.getDevice(deviceId); | |
| 623 | + OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam)hookParam; | |
| 625 | 624 | if (streamInfo != null) { |
| 626 | 625 | DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); |
| 627 | 626 | if (deviceChannel != null) { |
| ... | ... | @@ -639,9 +638,9 @@ public class PlayServiceImpl implements IPlayService { |
| 639 | 638 | |
| 640 | 639 | } |
| 641 | 640 | |
| 642 | - private StreamInfo onPublishHandlerForPlayback(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String startTime, String endTime) { | |
| 643 | - | |
| 644 | - StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId); | |
| 641 | + private StreamInfo onPublishHandlerForPlayback(MediaServerItem mediaServerItem, HookParam param, String deviceId, String channelId, String startTime, String endTime) { | |
| 642 | + OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam) param; | |
| 643 | + StreamInfo streamInfo = onPublishHandler(mediaServerItem, streamChangedHookParam, deviceId, channelId); | |
| 645 | 644 | if (streamInfo != null) { |
| 646 | 645 | streamInfo.setStartTime(startTime); |
| 647 | 646 | streamInfo.setEndTime(endTime); |
| ... | ... | @@ -698,7 +697,7 @@ public class PlayServiceImpl implements IPlayService { |
| 698 | 697 | |
| 699 | 698 | @Override |
| 700 | 699 | public void playBack(String deviceId, String channelId, String startTime, |
| 701 | - String endTime, InviteErrorCallback<Object> callback) { | |
| 700 | + String endTime, ErrorCallback<Object> callback) { | |
| 702 | 701 | Device device = storager.queryVideoDevice(deviceId); |
| 703 | 702 | if (device == null) { |
| 704 | 703 | return; |
| ... | ... | @@ -711,7 +710,7 @@ public class PlayServiceImpl implements IPlayService { |
| 711 | 710 | @Override |
| 712 | 711 | public void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, |
| 713 | 712 | String deviceId, String channelId, String startTime, |
| 714 | - String endTime, InviteErrorCallback<Object> callback) { | |
| 713 | + String endTime, ErrorCallback<Object> callback) { | |
| 715 | 714 | if (mediaServerItem == null || ssrcInfo == null) { |
| 716 | 715 | callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(), |
| 717 | 716 | InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(), |
| ... | ... | @@ -727,7 +726,7 @@ public class PlayServiceImpl implements IPlayService { |
| 727 | 726 | device.getDeviceId(), channelId, startTime, endTime, ssrcInfo.getPort(), device.getStreamMode(), |
| 728 | 727 | ssrcInfo.getSsrc(), device.isSsrcCheck()); |
| 729 | 728 | // 初始化redis中的invite消息状态 |
| 730 | - InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo, | |
| 729 | + InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo, | |
| 731 | 730 | mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAYBACK, |
| 732 | 731 | InviteSessionStatus.ready); |
| 733 | 732 | inviteStreamService.updateInviteInfo(inviteInfo); |
| ... | ... | @@ -760,10 +759,10 @@ public class PlayServiceImpl implements IPlayService { |
| 760 | 759 | inviteStreamService.removeInviteInfo(inviteInfo); |
| 761 | 760 | }; |
| 762 | 761 | |
| 763 | - ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, jsonObject) -> { | |
| 764 | - logger.info("收到回放订阅消息: " + jsonObject); | |
| 762 | + ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, hookParam) -> { | |
| 763 | + logger.info("收到回放订阅消息: " + hookParam); | |
| 765 | 764 | dynamicTask.stop(playBackTimeOutTaskKey); |
| 766 | - StreamInfo streamInfo = onPublishHandlerForPlayback(mediaServerItemInuse, jsonObject, deviceId, channelId, startTime, endTime); | |
| 765 | + StreamInfo streamInfo = onPublishHandlerForPlayback(mediaServerItemInuse, hookParam, deviceId, channelId, startTime, endTime); | |
| 767 | 766 | if (streamInfo == null) { |
| 768 | 767 | logger.warn("设备回放API调用失败!"); |
| 769 | 768 | callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(), |
| ... | ... | @@ -829,17 +828,8 @@ public class PlayServiceImpl implements IPlayService { |
| 829 | 828 | if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) { |
| 830 | 829 | logger.info("[录像回放] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); |
| 831 | 830 | |
| 832 | - if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) { | |
| 833 | - // ssrc 不可用 | |
| 834 | - logger.info("[录像回放] SSRC修正时发现ssrc不可使用 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); | |
| 835 | - // 释放ssrc | |
| 836 | - dynamicTask.stop(playBackTimeOutTaskKey); | |
| 837 | - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 838 | - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 839 | - callback.run(InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(), | |
| 840 | - InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null); | |
| 841 | - return; | |
| 842 | - } | |
| 831 | + // 释放ssrc | |
| 832 | + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 843 | 833 | |
| 844 | 834 | // 单端口模式streamId也有变化,需要重新设置监听 |
| 845 | 835 | if (!mediaServerItem.isRtpEnable()) { |
| ... | ... | @@ -848,12 +838,12 @@ public class PlayServiceImpl implements IPlayService { |
| 848 | 838 | subscribe.removeSubscribe(hookSubscribe); |
| 849 | 839 | String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase(); |
| 850 | 840 | hookSubscribe.getContent().put("stream", stream); |
| 851 | - inviteInfo.setStream(stream); | |
| 852 | - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> { | |
| 853 | - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString()); | |
| 841 | + inviteStreamService.updateInviteInfoForStream(inviteInfo, stream); | |
| 842 | + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> { | |
| 843 | + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam); | |
| 854 | 844 | dynamicTask.stop(playBackTimeOutTaskKey); |
| 855 | 845 | // hook响应 |
| 856 | - hookEvent.response(mediaServerItemInUse, response); | |
| 846 | + hookEvent.response(mediaServerItemInUse, hookParam); | |
| 857 | 847 | }); |
| 858 | 848 | } |
| 859 | 849 | // 更新ssrc |
| ... | ... | @@ -877,6 +867,10 @@ public class PlayServiceImpl implements IPlayService { |
| 877 | 867 | "下级自定义了ssrc,重新设置收流信息失败", null); |
| 878 | 868 | |
| 879 | 869 | }else { |
| 870 | + if (ssrcInfo.getStream()!= null && !ssrcInfo.getStream().equals(inviteInfo.getStream())) { | |
| 871 | + inviteStreamService.removeInviteInfo(inviteInfo); | |
| 872 | + } | |
| 873 | + | |
| 880 | 874 | ssrcInfo.setSsrc(ssrcInResponse); |
| 881 | 875 | inviteInfo.setSsrcInfo(ssrcInfo); |
| 882 | 876 | inviteInfo.setStream(ssrcInfo.getStream()); |
| ... | ... | @@ -900,7 +894,7 @@ public class PlayServiceImpl implements IPlayService { |
| 900 | 894 | |
| 901 | 895 | |
| 902 | 896 | @Override |
| 903 | - public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback) { | |
| 897 | + public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback) { | |
| 904 | 898 | Device device = storager.queryVideoDevice(deviceId); |
| 905 | 899 | if (device == null) { |
| 906 | 900 | return; |
| ... | ... | @@ -918,7 +912,7 @@ public class PlayServiceImpl implements IPlayService { |
| 918 | 912 | |
| 919 | 913 | |
| 920 | 914 | @Override |
| 921 | - public void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback) { | |
| 915 | + public void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback) { | |
| 922 | 916 | if (mediaServerItem == null || ssrcInfo == null) { |
| 923 | 917 | callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(), |
| 924 | 918 | InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(), |
| ... | ... | @@ -934,7 +928,7 @@ public class PlayServiceImpl implements IPlayService { |
| 934 | 928 | } |
| 935 | 929 | logger.info("[录像下载] deviceId: {}, channelId: {}, 下载速度:{}, 收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, downloadSpeed, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); |
| 936 | 930 | // 初始化redis中的invite消息状态 |
| 937 | - InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo, | |
| 931 | + InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo, | |
| 938 | 932 | mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD, |
| 939 | 933 | InviteSessionStatus.ready); |
| 940 | 934 | inviteStreamService.updateInviteInfo(inviteInfo); |
| ... | ... | @@ -964,10 +958,10 @@ public class PlayServiceImpl implements IPlayService { |
| 964 | 958 | streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); |
| 965 | 959 | inviteStreamService.removeInviteInfo(inviteInfo); |
| 966 | 960 | }; |
| 967 | - ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, jsonObject) -> { | |
| 968 | - logger.info("[录像下载]收到订阅消息: " + jsonObject); | |
| 961 | + ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, hookParam) -> { | |
| 962 | + logger.info("[录像下载]收到订阅消息: " + hookParam); | |
| 969 | 963 | dynamicTask.stop(downLoadTimeOutTaskKey); |
| 970 | - StreamInfo streamInfo = onPublishHandlerForDownload(mediaServerItemInuse, jsonObject, deviceId, channelId, startTime, endTime); | |
| 964 | + StreamInfo streamInfo = onPublishHandlerForDownload(mediaServerItemInuse, hookParam, deviceId, channelId, startTime, endTime); | |
| 971 | 965 | if (streamInfo == null) { |
| 972 | 966 | logger.warn("[录像下载] 获取流地址信息失败"); |
| 973 | 967 | callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(), |
| ... | ... | @@ -1032,26 +1026,21 @@ public class PlayServiceImpl implements IPlayService { |
| 1032 | 1026 | if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) { |
| 1033 | 1027 | logger.info("[录像下载] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse); |
| 1034 | 1028 | |
| 1035 | - if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) { | |
| 1036 | - // ssrc 不可用 | |
| 1037 | - // 释放ssrc | |
| 1038 | - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 1039 | - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 1040 | - callback.run(InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(), | |
| 1041 | - InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null); | |
| 1042 | - return; | |
| 1043 | - } | |
| 1029 | + // 释放ssrc | |
| 1030 | + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 1044 | 1031 | |
| 1045 | 1032 | // 单端口模式streamId也有变化,需要重新设置监听 |
| 1046 | 1033 | if (!mediaServerItem.isRtpEnable()) { |
| 1047 | 1034 | // 添加订阅 |
| 1048 | 1035 | HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); |
| 1049 | 1036 | subscribe.removeSubscribe(hookSubscribe); |
| 1050 | - hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase()); | |
| 1051 | - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> { | |
| 1052 | - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString()); | |
| 1037 | + String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase(); | |
| 1038 | + hookSubscribe.getContent().put("stream", stream); | |
| 1039 | + inviteStreamService.updateInviteInfoForStream(inviteInfo, stream); | |
| 1040 | + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> { | |
| 1041 | + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam); | |
| 1053 | 1042 | dynamicTask.stop(downLoadTimeOutTaskKey); |
| 1054 | - hookEvent.response(mediaServerItemInUse, response); | |
| 1043 | + hookEvent.response(mediaServerItemInUse, hookParam); | |
| 1055 | 1044 | }); |
| 1056 | 1045 | } |
| 1057 | 1046 | |
| ... | ... | @@ -1075,6 +1064,9 @@ public class PlayServiceImpl implements IPlayService { |
| 1075 | 1064 | "下级自定义了ssrc,重新设置收流信息失败", null); |
| 1076 | 1065 | |
| 1077 | 1066 | }else { |
| 1067 | + if (ssrcInfo.getStream()!= null && !ssrcInfo.getStream().equals(inviteInfo.getStream())) { | |
| 1068 | + inviteStreamService.removeInviteInfo(inviteInfo); | |
| 1069 | + } | |
| 1078 | 1070 | ssrcInfo.setSsrc(ssrcInResponse); |
| 1079 | 1071 | inviteInfo.setSsrcInfo(ssrcInfo); |
| 1080 | 1072 | inviteInfo.setStream(ssrcInfo.getStream()); |
| ... | ... | @@ -1083,6 +1075,7 @@ public class PlayServiceImpl implements IPlayService { |
| 1083 | 1075 | logger.info("[录像下载] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正"); |
| 1084 | 1076 | } |
| 1085 | 1077 | } |
| 1078 | + inviteStreamService.updateInviteInfo(inviteInfo); | |
| 1086 | 1079 | }); |
| 1087 | 1080 | } catch (InvalidArgumentException | SipException | ParseException e) { |
| 1088 | 1081 | logger.error("[命令发送失败] 录像下载: {}", e.getMessage()); |
| ... | ... | @@ -1141,8 +1134,9 @@ public class PlayServiceImpl implements IPlayService { |
| 1141 | 1134 | return null; |
| 1142 | 1135 | } |
| 1143 | 1136 | |
| 1144 | - private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, JSONObject response, String deviceId, String channelId, String startTime, String endTime) { | |
| 1145 | - StreamInfo streamInfo = onPublishHandler(mediaServerItemInuse, response, deviceId, channelId); | |
| 1137 | + private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, HookParam hookParam, String deviceId, String channelId, String startTime, String endTime) { | |
| 1138 | + OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam) hookParam; | |
| 1139 | + StreamInfo streamInfo = onPublishHandler(mediaServerItemInuse, streamChangedHookParam, deviceId, channelId); | |
| 1146 | 1140 | if (streamInfo != null) { |
| 1147 | 1141 | streamInfo.setProgress(0); |
| 1148 | 1142 | streamInfo.setStartTime(startTime); |
| ... | ... | @@ -1159,15 +1153,14 @@ public class PlayServiceImpl implements IPlayService { |
| 1159 | 1153 | } |
| 1160 | 1154 | |
| 1161 | 1155 | |
| 1162 | - public StreamInfo onPublishHandler(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId) { | |
| 1163 | - String streamId = resonse.getString("stream"); | |
| 1164 | - JSONArray tracks = resonse.getJSONArray("tracks"); | |
| 1165 | - StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem, "rtp", streamId, tracks, null); | |
| 1156 | + public StreamInfo onPublishHandler(MediaServerItem mediaServerItem, OnStreamChangedHookParam hookParam, String deviceId, String channelId) { | |
| 1157 | + StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem, "rtp", hookParam.getStream(), hookParam.getTracks(), null); | |
| 1166 | 1158 | streamInfo.setDeviceID(deviceId); |
| 1167 | 1159 | streamInfo.setChannelId(channelId); |
| 1168 | 1160 | return streamInfo; |
| 1169 | 1161 | } |
| 1170 | 1162 | |
| 1163 | + | |
| 1171 | 1164 | @Override |
| 1172 | 1165 | public void zlmServerOffline(String mediaServerId) { |
| 1173 | 1166 | // 处理正在向上推流的上级平台 |
| ... | ... | @@ -1635,4 +1628,52 @@ public class PlayServiceImpl implements IPlayService { |
| 1635 | 1628 | } |
| 1636 | 1629 | redisCatchStorage.deleteSendRTPServer(device.getDeviceId(), channelId,null, null); |
| 1637 | 1630 | } |
| 1631 | + | |
| 1632 | + @Override | |
| 1633 | + public void getSnap(String deviceId, String channelId, String fileName, ErrorCallback errorCallback) { | |
| 1634 | + Device device = deviceService.getDevice(deviceId); | |
| 1635 | + if (device == null) { | |
| 1636 | + errorCallback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(), InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(), null); | |
| 1637 | + return; | |
| 1638 | + } | |
| 1639 | + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId); | |
| 1640 | + if (inviteInfo != null) { | |
| 1641 | + if (inviteInfo.getStreamInfo() != null) { | |
| 1642 | + // 已存在线直接截图 | |
| 1643 | + MediaServerItem mediaServerItemInuse = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId()); | |
| 1644 | + String streamUrl; | |
| 1645 | + if (mediaServerItemInuse.getRtspPort() != 0) { | |
| 1646 | + streamUrl = String.format("rtsp://127.0.0.1:%s/%s/%s", mediaServerItemInuse.getRtspPort(), "rtp", inviteInfo.getStreamInfo().getStream()); | |
| 1647 | + }else { | |
| 1648 | + streamUrl = String.format("http://127.0.0.1:%s/%s/%s.live.mp4", mediaServerItemInuse.getHttpPort(), "rtp", inviteInfo.getStreamInfo().getStream()); | |
| 1649 | + } | |
| 1650 | + String path = "snap"; | |
| 1651 | + // 请求截图 | |
| 1652 | + logger.info("[请求截图]: " + fileName); | |
| 1653 | + zlmresTfulUtils.getSnap(mediaServerItemInuse, streamUrl, 15, 1, path, fileName); | |
| 1654 | + File snapFile = new File(path + File.separator + fileName); | |
| 1655 | + if (snapFile.exists()) { | |
| 1656 | + errorCallback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), snapFile.getAbsoluteFile()); | |
| 1657 | + }else { | |
| 1658 | + errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null); | |
| 1659 | + } | |
| 1660 | + return; | |
| 1661 | + } | |
| 1662 | + } | |
| 1663 | + | |
| 1664 | + MediaServerItem newMediaServerItem = getNewMediaServerItem(device); | |
| 1665 | + play(newMediaServerItem, deviceId, channelId, (code, msg, data)->{ | |
| 1666 | + if (code == InviteErrorCode.SUCCESS.getCode()) { | |
| 1667 | + InviteInfo inviteInfoForPlay = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId); | |
| 1668 | + if (inviteInfoForPlay != null && inviteInfoForPlay.getStreamInfo() != null) { | |
| 1669 | + getSnap(deviceId, channelId, fileName, errorCallback); | |
| 1670 | + }else { | |
| 1671 | + errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null); | |
| 1672 | + } | |
| 1673 | + }else { | |
| 1674 | + errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null); | |
| 1675 | + } | |
| 1676 | + }); | |
| 1677 | + } | |
| 1678 | + | |
| 1638 | 1679 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/RecordInfoServerImpl.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.service.impl; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.service.IRecordInfoServer; | |
| 4 | -import com.genersoft.iot.vmp.storager.dao.RecordInfoDao; | |
| 5 | -import com.genersoft.iot.vmp.storager.dao.dto.RecordInfo; | |
| 6 | -import com.github.pagehelper.PageHelper; | |
| 7 | -import com.github.pagehelper.PageInfo; | |
| 8 | -import org.springframework.beans.factory.annotation.Autowired; | |
| 9 | -import org.springframework.stereotype.Service; | |
| 10 | - | |
| 11 | -import java.util.List; | |
| 12 | - | |
| 13 | -@Service | |
| 14 | -public class RecordInfoServerImpl implements IRecordInfoServer { | |
| 15 | - | |
| 16 | - @Autowired | |
| 17 | - private RecordInfoDao recordInfoDao; | |
| 18 | - | |
| 19 | - @Override | |
| 20 | - public PageInfo<RecordInfo> getRecordList(int page, int count) { | |
| 21 | - PageHelper.startPage(page, count); | |
| 22 | - List<RecordInfo> all = recordInfoDao.selectAll(); | |
| 23 | - return new PageInfo<>(all); | |
| 24 | - } | |
| 25 | -} |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
| ... | ... | @@ -2,12 +2,16 @@ package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | |
| 3 | 3 | import com.alibaba.fastjson2.JSONArray; |
| 4 | 4 | import com.alibaba.fastjson2.JSONObject; |
| 5 | +import com.genersoft.iot.vmp.common.GeneralCallback; | |
| 5 | 6 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 6 | 7 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 7 | 8 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 8 | 9 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| 9 | 10 | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
| 10 | 11 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| 12 | +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; | |
| 13 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; | |
| 14 | +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; | |
| 11 | 15 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 12 | 16 | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; |
| 13 | 17 | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; |
| ... | ... | @@ -23,7 +27,7 @@ import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper; |
| 23 | 27 | import com.genersoft.iot.vmp.storager.dao.StreamProxyMapper; |
| 24 | 28 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 25 | 29 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 26 | -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; | |
| 30 | +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; | |
| 27 | 31 | import com.github.pagehelper.PageInfo; |
| 28 | 32 | import org.slf4j.Logger; |
| 29 | 33 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -80,6 +84,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 80 | 84 | private IMediaServerService mediaServerService; |
| 81 | 85 | |
| 82 | 86 | @Autowired |
| 87 | + private ZlmHttpHookSubscribe hookSubscribe; | |
| 88 | + | |
| 89 | + @Autowired | |
| 83 | 90 | DataSourceTransactionManager dataSourceTransactionManager; |
| 84 | 91 | |
| 85 | 92 | @Autowired |
| ... | ... | @@ -87,7 +94,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 87 | 94 | |
| 88 | 95 | |
| 89 | 96 | @Override |
| 90 | - public StreamInfo save(StreamProxyItem param) { | |
| 97 | + public void save(StreamProxyItem param, GeneralCallback<StreamInfo> callback) { | |
| 91 | 98 | MediaServerItem mediaInfo; |
| 92 | 99 | if (ObjectUtils.isEmpty(param.getMediaServerId()) || "auto".equals(param.getMediaServerId())){ |
| 93 | 100 | mediaInfo = mediaServerService.getMediaServerForMinimumLoad(null); |
| ... | ... | @@ -98,10 +105,43 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 98 | 105 | logger.warn("保存代理未找到在线的ZLM..."); |
| 99 | 106 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "保存代理未找到在线的ZLM"); |
| 100 | 107 | } |
| 101 | - String dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(), | |
| 102 | - param.getStream() ); | |
| 103 | - param.setDst_url(dstUrl); | |
| 104 | - StringBuffer resultMsg = new StringBuffer(); | |
| 108 | + String dstUrl; | |
| 109 | + if ("ffmpeg".equalsIgnoreCase(param.getType())) { | |
| 110 | + JSONObject jsonObject = zlmresTfulUtils.getMediaServerConfig(mediaInfo); | |
| 111 | + if (jsonObject.getInteger("code") != 0) { | |
| 112 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取流媒体配置失败"); | |
| 113 | + } | |
| 114 | + JSONArray dataArray = jsonObject.getJSONArray("data"); | |
| 115 | + JSONObject mediaServerConfig = dataArray.getJSONObject(0); | |
| 116 | + String ffmpegCmd = mediaServerConfig.getString(param.getFfmpegCmdKey()); | |
| 117 | + String schema = getSchemaFromFFmpegCmd(ffmpegCmd); | |
| 118 | + if (schema == null) { | |
| 119 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "ffmpeg拉流代理无法从ffmpeg cmd中获取到输出格式"); | |
| 120 | + } | |
| 121 | + int port; | |
| 122 | + String schemaForUri; | |
| 123 | + if (schema.equalsIgnoreCase("rtsp")) { | |
| 124 | + port = mediaInfo.getRtspPort(); | |
| 125 | + schemaForUri = schema; | |
| 126 | + }else if (schema.equalsIgnoreCase("flv")) { | |
| 127 | + port = mediaInfo.getHttpPort(); | |
| 128 | + schemaForUri = "http"; | |
| 129 | + }else if (schema.equalsIgnoreCase("rtmp")) { | |
| 130 | + port = mediaInfo.getRtmpPort(); | |
| 131 | + schemaForUri = schema; | |
| 132 | + }else { | |
| 133 | + port = mediaInfo.getRtmpPort(); | |
| 134 | + schemaForUri = schema; | |
| 135 | + } | |
| 136 | + | |
| 137 | + dstUrl = String.format("%s://%s:%s/%s/%s", schemaForUri, "127.0.0.1", port, param.getApp(), | |
| 138 | + param.getStream()); | |
| 139 | + }else { | |
| 140 | + dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(), | |
| 141 | + param.getStream()); | |
| 142 | + } | |
| 143 | + param.setDstUrl(dstUrl); | |
| 144 | + logger.info("[拉流代理] 输出地址为:{}", dstUrl); | |
| 105 | 145 | param.setMediaServerId(mediaInfo.getId()); |
| 106 | 146 | boolean saveResult; |
| 107 | 147 | // 更新 |
| ... | ... | @@ -111,29 +151,60 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 111 | 151 | saveResult = addStreamProxy(param); |
| 112 | 152 | } |
| 113 | 153 | if (!saveResult) { |
| 114 | - throw new ControllerException(ErrorCode.ERROR100.getCode(),"保存失败"); | |
| 154 | + callback.run(ErrorCode.ERROR100.getCode(), "保存失败", null); | |
| 155 | + return; | |
| 115 | 156 | } |
| 116 | - StreamInfo resultForStreamInfo = null; | |
| 117 | - resultMsg.append("保存成功"); | |
| 157 | + | |
| 158 | + HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed(param.getApp(), param.getStream(), true, "rtsp", mediaInfo.getId()); | |
| 159 | + hookSubscribe.addSubscribe(hookSubscribeForStreamChange, (mediaServerItem, response) -> { | |
| 160 | + StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream( | |
| 161 | + mediaInfo, param.getApp(), param.getStream(), null, null); | |
| 162 | + callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo); | |
| 163 | + }); | |
| 164 | + | |
| 118 | 165 | if (param.isEnable()) { |
| 119 | 166 | JSONObject jsonObject = addStreamProxyToZlm(param); |
| 120 | - if (jsonObject == null || jsonObject.getInteger("code") != 0) { | |
| 121 | - resultMsg.append(", 但是启用失败,请检查流地址是否可用"); | |
| 167 | + if (jsonObject != null && jsonObject.getInteger("code") == 0) { | |
| 168 | + hookSubscribe.removeSubscribe(hookSubscribeForStreamChange); | |
| 169 | + StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream( | |
| 170 | + mediaInfo, param.getApp(), param.getStream(), null, null); | |
| 171 | + callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo); | |
| 172 | + }else { | |
| 122 | 173 | param.setEnable(false); |
| 123 | 174 | // 直接移除 |
| 124 | - if (param.isEnable_remove_none_reader()) { | |
| 175 | + if (param.isEnableRemoveNoneReader()) { | |
| 125 | 176 | del(param.getApp(), param.getStream()); |
| 126 | 177 | }else { |
| 127 | 178 | updateStreamProxy(param); |
| 128 | 179 | } |
| 180 | + if (jsonObject == null){ | |
| 181 | + callback.run(ErrorCode.ERROR100.getCode(), "记录已保存,启用失败", null); | |
| 182 | + return; | |
| 183 | + }else { | |
| 184 | + callback.run(ErrorCode.ERROR100.getCode(), jsonObject.getString("msg"), null); | |
| 185 | + return; | |
| 186 | + } | |
| 187 | + } | |
| 188 | + } | |
| 189 | + } | |
| 129 | 190 | |
| 130 | - }else { | |
| 131 | - resultForStreamInfo = mediaService.getStreamInfoByAppAndStream( | |
| 132 | - mediaInfo, param.getApp(), param.getStream(), null, null); | |
| 191 | + private String getSchemaFromFFmpegCmd(String ffmpegCmd) { | |
| 192 | + ffmpegCmd = ffmpegCmd.replaceAll(" + ", " "); | |
| 193 | + String[] paramArray = ffmpegCmd.split(" "); | |
| 194 | + if (paramArray.length == 0) { | |
| 195 | + return null; | |
| 196 | + } | |
| 197 | + for (int i = 0; i < paramArray.length; i++) { | |
| 198 | + if (paramArray[i].equalsIgnoreCase("-f")) { | |
| 199 | + if (i + 1 < paramArray.length - 1) { | |
| 200 | + return paramArray[i+1]; | |
| 201 | + }else { | |
| 202 | + return null; | |
| 203 | + } | |
| 133 | 204 | |
| 134 | 205 | } |
| 135 | 206 | } |
| 136 | - return resultForStreamInfo; | |
| 207 | + return null; | |
| 137 | 208 | } |
| 138 | 209 | |
| 139 | 210 | /** |
| ... | ... | @@ -222,11 +293,11 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 222 | 293 | } |
| 223 | 294 | if ("default".equals(param.getType())){ |
| 224 | 295 | result = zlmresTfulUtils.addStreamProxy(mediaServerItem, param.getApp(), param.getStream(), param.getUrl(), |
| 225 | - param.isEnable_audio(), param.isEnable_mp4(), param.getRtp_type()); | |
| 296 | + param.isEnableAudio(), param.isEnableMp4(), param.getRtpType()); | |
| 226 | 297 | }else if ("ffmpeg".equals(param.getType())) { |
| 227 | - result = zlmresTfulUtils.addFFmpegSource(mediaServerItem, param.getSrc_url(), param.getDst_url(), | |
| 228 | - param.getTimeout_ms() + "", param.isEnable_audio(), param.isEnable_mp4(), | |
| 229 | - param.getFfmpeg_cmd_key()); | |
| 298 | + result = zlmresTfulUtils.addFFmpegSource(mediaServerItem, param.getSrcUrl(), param.getDstUrl(), | |
| 299 | + param.getTimeoutMs() + "", param.isEnableAudio(), param.isEnableMp4(), | |
| 300 | + param.getFfmpegCmdKey()); | |
| 230 | 301 | } |
| 231 | 302 | return result; |
| 232 | 303 | } |
| ... | ... | @@ -280,7 +351,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 280 | 351 | updateStreamProxy(streamProxy); |
| 281 | 352 | }else { |
| 282 | 353 | logger.info("启用代理失败: {}/{}->{}({})", app, stream, jsonObject.getString("msg"), |
| 283 | - streamProxy.getSrc_url() == null? streamProxy.getUrl():streamProxy.getSrc_url()); | |
| 354 | + streamProxy.getSrcUrl() == null? streamProxy.getUrl():streamProxy.getSrcUrl()); | |
| 284 | 355 | } |
| 285 | 356 | } |
| 286 | 357 | return result; |
| ... | ... | @@ -326,7 +397,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 326 | 397 | @Override |
| 327 | 398 | public void zlmServerOnline(String mediaServerId) { |
| 328 | 399 | // 移除开启了无人观看自动移除的流 |
| 329 | - List<StreamProxyItem> streamProxyItemList = streamProxyMapper.selecAutoRemoveItemByMediaServerId(mediaServerId); | |
| 400 | + List<StreamProxyItem> streamProxyItemList = streamProxyMapper.selectAutoRemoveItemByMediaServerId(mediaServerId); | |
| 330 | 401 | if (streamProxyItemList.size() > 0) { |
| 331 | 402 | gbStreamMapper.batchDel(streamProxyItemList); |
| 332 | 403 | } |
| ... | ... | @@ -354,7 +425,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 354 | 425 | @Override |
| 355 | 426 | public void zlmServerOffline(String mediaServerId) { |
| 356 | 427 | // 移除开启了无人观看自动移除的流 |
| 357 | - List<StreamProxyItem> streamProxyItemList = streamProxyMapper.selecAutoRemoveItemByMediaServerId(mediaServerId); | |
| 428 | + List<StreamProxyItem> streamProxyItemList = streamProxyMapper.selectAutoRemoveItemByMediaServerId(mediaServerId); | |
| 358 | 429 | if (streamProxyItemList.size() > 0) { |
| 359 | 430 | gbStreamMapper.batchDel(streamProxyItemList); |
| 360 | 431 | } |
| ... | ... | @@ -432,7 +503,11 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 432 | 503 | } |
| 433 | 504 | |
| 434 | 505 | @Override |
| 435 | - public ResourceBaceInfo getOverview() { | |
| 436 | - return streamProxyMapper.getOverview(); | |
| 506 | + public ResourceBaseInfo getOverview() { | |
| 507 | + | |
| 508 | + int total = streamProxyMapper.getAllCount(); | |
| 509 | + int online = streamProxyMapper.getOnline(); | |
| 510 | + | |
| 511 | + return new ResourceBaseInfo(total, online); | |
| 437 | 512 | } |
| 438 | 513 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
| ... | ... | @@ -20,7 +20,7 @@ import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; |
| 20 | 20 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 21 | 21 | import com.genersoft.iot.vmp.storager.dao.*; |
| 22 | 22 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 23 | -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; | |
| 23 | +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; | |
| 24 | 24 | import com.github.pagehelper.PageHelper; |
| 25 | 25 | import com.github.pagehelper.PageInfo; |
| 26 | 26 | import org.slf4j.Logger; |
| ... | ... | @@ -183,6 +183,7 @@ public class StreamPushServiceImpl implements IStreamPushService { |
| 183 | 183 | |
| 184 | 184 | @Override |
| 185 | 185 | public boolean stop(String app, String streamId) { |
| 186 | + logger.info("[推流 ] 停止流: {}/{}", app, streamId); | |
| 186 | 187 | StreamPushItem streamPushItem = streamPushMapper.selectOne(app, streamId); |
| 187 | 188 | if (streamPushItem != null) { |
| 188 | 189 | gbStreamService.sendCatalogMsg(streamPushItem, CatalogEvent.DEL); |
| ... | ... | @@ -531,7 +532,10 @@ public class StreamPushServiceImpl implements IStreamPushService { |
| 531 | 532 | } |
| 532 | 533 | |
| 533 | 534 | @Override |
| 534 | - public ResourceBaceInfo getOverview() { | |
| 535 | - return streamPushMapper.getOverview(userSetting.isUsePushingAsStatus()); | |
| 535 | + public ResourceBaseInfo getOverview() { | |
| 536 | + int total = streamPushMapper.getAllCount(); | |
| 537 | + int online = streamPushMapper.getAllOnline(userSetting.isUsePushingAsStatus()); | |
| 538 | + | |
| 539 | + return new ResourceBaseInfo(total, online); | |
| 536 | 540 | } |
| 537 | 541 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java
| ... | ... | @@ -9,7 +9,6 @@ import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto; |
| 9 | 9 | import com.google.common.collect.BiMap; |
| 10 | 10 | import com.google.common.collect.HashBiMap; |
| 11 | 11 | import org.springframework.util.ObjectUtils; |
| 12 | -import org.springframework.util.StringUtils; | |
| 13 | 12 | |
| 14 | 13 | import java.util.*; |
| 15 | 14 | |
| ... | ... | @@ -33,38 +32,43 @@ public class StreamPushUploadFileHandler extends AnalysisEventListener<StreamPus |
| 33 | 32 | /** |
| 34 | 33 | * 用于存储不加过滤的所有数据 |
| 35 | 34 | */ |
| 36 | - private List<StreamPushItem> streamPushItems = new ArrayList<>(); | |
| 35 | + private final List<StreamPushItem> streamPushItems = new ArrayList<>(); | |
| 37 | 36 | |
| 38 | 37 | /** |
| 39 | 38 | * 用于存储更具APP+Stream过滤后的数据,可以直接存入stream_push表与gb_stream表 |
| 40 | 39 | */ |
| 41 | - private Map<String,StreamPushItem> streamPushItemForSave = new HashMap<>(); | |
| 40 | + private final Map<String,StreamPushItem> streamPushItemForSave = new HashMap<>(); | |
| 42 | 41 | |
| 43 | 42 | /** |
| 44 | 43 | * 用于存储按照APP+Stream为KEY, 平台ID+目录Id 为value的数据,用于存储到gb_stream表后获取app+Stream对应的平台与目录信息,然后存入关联表 |
| 45 | 44 | */ |
| 46 | - private Map<String, List<String[]>> streamPushItemsForPlatform = new HashMap<>(); | |
| 45 | + private final Map<String, List<String[]>> streamPushItemsForPlatform = new HashMap<>(); | |
| 47 | 46 | |
| 48 | 47 | /** |
| 49 | 48 | * 用于判断文件是否存在重复的app+Stream+平台ID |
| 50 | 49 | */ |
| 51 | - private Set<String> streamPushStreamSet = new HashSet<>(); | |
| 50 | + private final Set<String> streamPushStreamSet = new HashSet<>(); | |
| 52 | 51 | |
| 53 | 52 | /** |
| 54 | 53 | * 用于存储APP+Stream->国标ID 的数据结构, 数据一一对应,全局判断APP+Stream->国标ID是否存在不对应 |
| 55 | 54 | */ |
| 56 | - private BiMap<String,String> gBMap = HashBiMap.create(); | |
| 55 | + private final BiMap<String,String> gBMap = HashBiMap.create(); | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * 用于存储APP+Stream-> 在数据库中的数据 | |
| 59 | + */ | |
| 60 | + private final BiMap<String,String> pushMapInDb = HashBiMap.create(); | |
| 57 | 61 | |
| 58 | 62 | /** |
| 59 | 63 | * 记录错误的APP+Stream |
| 60 | 64 | */ |
| 61 | - private List<String> errorStreamList = new ArrayList<>(); | |
| 65 | + private final List<String> errorStreamList = new ArrayList<>(); | |
| 62 | 66 | |
| 63 | 67 | |
| 64 | 68 | /** |
| 65 | 69 | * 记录错误的国标ID |
| 66 | 70 | */ |
| 67 | - private List<String> errorGBList = new ArrayList<>(); | |
| 71 | + private final List<String> errorInfoList = new ArrayList<>(); | |
| 68 | 72 | |
| 69 | 73 | /** |
| 70 | 74 | * 读取数量计数器 |
| ... | ... | @@ -75,6 +79,13 @@ public class StreamPushUploadFileHandler extends AnalysisEventListener<StreamPus |
| 75 | 79 | this.pushService = pushService; |
| 76 | 80 | this.defaultMediaServerId = defaultMediaServerId; |
| 77 | 81 | this.errorDataHandler = errorDataHandler; |
| 82 | + // 获取数据库已有的数据,已经存在的则忽略 | |
| 83 | + List<String> allAppAndStreams = pushService.getAllAppAndStream(); | |
| 84 | + if (allAppAndStreams.size() > 0) { | |
| 85 | + for (String allAppAndStream : allAppAndStreams) { | |
| 86 | + pushMapInDb.put(allAppAndStream, allAppAndStream); | |
| 87 | + } | |
| 88 | + } | |
| 78 | 89 | } |
| 79 | 90 | |
| 80 | 91 | public interface ErrorDataHandler{ |
| ... | ... | @@ -88,26 +99,30 @@ public class StreamPushUploadFileHandler extends AnalysisEventListener<StreamPus |
| 88 | 99 | || ObjectUtils.isEmpty(streamPushExcelDto.getGbId())) { |
| 89 | 100 | return; |
| 90 | 101 | } |
| 102 | + Integer rowIndex = analysisContext.readRowHolder().getRowIndex(); | |
| 91 | 103 | |
| 92 | 104 | if (gBMap.get(streamPushExcelDto.getApp() + streamPushExcelDto.getStream()) == null) { |
| 93 | 105 | try { |
| 94 | 106 | gBMap.put(streamPushExcelDto.getApp() + streamPushExcelDto.getStream(), streamPushExcelDto.getGbId()); |
| 95 | 107 | }catch (IllegalArgumentException e) { |
| 96 | - errorGBList.add(streamPushExcelDto.getGbId() + "(不同的app+stream使用了相同的国标ID)"); | |
| 108 | + errorInfoList.add("行:" + rowIndex + ", " + streamPushExcelDto.getGbId() + " 国标ID重复使用"); | |
| 97 | 109 | return; |
| 98 | 110 | } |
| 99 | 111 | }else { |
| 100 | 112 | if (!gBMap.get(streamPushExcelDto.getApp() + streamPushExcelDto.getStream()).equals(streamPushExcelDto.getGbId())) { |
| 101 | - errorGBList.add(streamPushExcelDto.getGbId() + "(同一组app+stream使用了不同的国标ID)"); | |
| 113 | + errorInfoList.add("行:" + rowIndex + ", " + streamPushExcelDto.getGbId() + " 同样的应用名和流ID使用了不同的国标ID"); | |
| 102 | 114 | return; |
| 103 | 115 | } |
| 104 | 116 | } |
| 105 | 117 | |
| 106 | 118 | if (streamPushStreamSet.contains(streamPushExcelDto.getApp() + streamPushExcelDto.getStream() + streamPushExcelDto.getPlatformId())) { |
| 107 | - errorStreamList.add(streamPushExcelDto.getApp() + "/" + streamPushExcelDto.getStream()+ "/" + | |
| 108 | - streamPushExcelDto.getPlatformId() + "(同一组app+stream添加在了同一个平台下)"); | |
| 119 | + errorStreamList.add("行:" + rowIndex + ", " + streamPushExcelDto.getApp() + "/" + streamPushExcelDto.getStream()+ " 平台信息重复"); | |
| 109 | 120 | return; |
| 110 | 121 | }else { |
| 122 | + if (pushMapInDb.get(streamPushExcelDto.getApp()+streamPushExcelDto.getStream()) != null) { | |
| 123 | + errorStreamList.add("行:" + rowIndex + ", " + streamPushExcelDto.getApp() + "/" + streamPushExcelDto.getStream()+ " 数据已存在"); | |
| 124 | + return; | |
| 125 | + } | |
| 111 | 126 | streamPushStreamSet.add(streamPushExcelDto.getApp()+streamPushExcelDto.getStream() + streamPushExcelDto.getPlatformId()); |
| 112 | 127 | } |
| 113 | 128 | |
| ... | ... | @@ -165,7 +180,7 @@ public class StreamPushUploadFileHandler extends AnalysisEventListener<StreamPus |
| 165 | 180 | gBMap.clear(); |
| 166 | 181 | streamPushStreamSet.clear(); |
| 167 | 182 | streamPushItemsForPlatform.clear(); |
| 168 | - errorDataHandler.handle(errorStreamList, errorGBList); | |
| 183 | + errorDataHandler.handle(errorStreamList, errorInfoList); | |
| 169 | 184 | } |
| 170 | 185 | |
| 171 | 186 | private void saveData(){ | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java
| ... | ... | @@ -7,8 +7,7 @@ import com.github.pagehelper.PageHelper; |
| 7 | 7 | import com.github.pagehelper.PageInfo; |
| 8 | 8 | import org.springframework.beans.factory.annotation.Autowired; |
| 9 | 9 | import org.springframework.stereotype.Service; |
| 10 | -import org.springframework.util.ObjectUtils; | |
| 11 | -import org.springframework.util.StringUtils; | |
| 10 | +import org.springframework.util.DigestUtils; | |
| 12 | 11 | |
| 13 | 12 | import java.util.List; |
| 14 | 13 | |
| ... | ... | @@ -61,11 +60,22 @@ public class UserServiceImpl implements IUserService { |
| 61 | 60 | |
| 62 | 61 | @Override |
| 63 | 62 | public boolean checkPushAuthority(String callId, String sign) { |
| 64 | - if (ObjectUtils.isEmpty(callId)) { | |
| 65 | - return userMapper.checkPushAuthorityByCallId(sign).size() > 0; | |
| 66 | - }else { | |
| 67 | - return userMapper.checkPushAuthorityByCallIdAndSign(callId, sign).size() > 0; | |
| 63 | + | |
| 64 | + List<User> users = userMapper.getUsers(); | |
| 65 | + if (users.size() == 0) { | |
| 66 | + return false; | |
| 67 | + } | |
| 68 | + for (User user : users) { | |
| 69 | + if (user.getPushKey() == null) { | |
| 70 | + continue; | |
| 71 | + } | |
| 72 | + String checkStr = callId == null? user.getPushKey():(callId + "_" + user.getPushKey()) ; | |
| 73 | + String checkSign = DigestUtils.md5DigestAsHex(checkStr.getBytes()); | |
| 74 | + if (checkSign.equals(sign)) { | |
| 75 | + return true; | |
| 76 | + } | |
| 68 | 77 | } |
| 78 | + return false; | |
| 69 | 79 | } |
| 70 | 80 | |
| 71 | 81 | @Override | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.service.redisMsg; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson2.JSON; | |
| 4 | +import com.alibaba.fastjson2.JSONObject; | |
| 5 | +import com.genersoft.iot.vmp.service.IStreamPushService; | |
| 6 | +import org.jetbrains.annotations.NotNull; | |
| 7 | +import org.slf4j.Logger; | |
| 8 | +import org.slf4j.LoggerFactory; | |
| 9 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 10 | +import org.springframework.beans.factory.annotation.Qualifier; | |
| 11 | +import org.springframework.data.redis.connection.Message; | |
| 12 | +import org.springframework.data.redis.connection.MessageListener; | |
| 13 | +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | |
| 14 | +import org.springframework.stereotype.Component; | |
| 15 | + | |
| 16 | +import java.util.concurrent.ConcurrentLinkedQueue; | |
| 17 | + | |
| 18 | +/** | |
| 19 | + * 接收来自redis的关闭流更新通知 | |
| 20 | + * @author lin | |
| 21 | + */ | |
| 22 | +@Component | |
| 23 | +public class RedisCloseStreamMsgListener implements MessageListener { | |
| 24 | + | |
| 25 | + private final static Logger logger = LoggerFactory.getLogger(RedisCloseStreamMsgListener.class); | |
| 26 | + | |
| 27 | + | |
| 28 | + @Autowired | |
| 29 | + private IStreamPushService pushService; | |
| 30 | + | |
| 31 | + private ConcurrentLinkedQueue<Message> taskQueue = new ConcurrentLinkedQueue<>(); | |
| 32 | + | |
| 33 | + @Qualifier("taskExecutor") | |
| 34 | + @Autowired | |
| 35 | + private ThreadPoolTaskExecutor taskExecutor; | |
| 36 | + | |
| 37 | + @Override | |
| 38 | + public void onMessage(@NotNull Message message, byte[] bytes) { | |
| 39 | + boolean isEmpty = taskQueue.isEmpty(); | |
| 40 | + taskQueue.offer(message); | |
| 41 | + if (isEmpty) { | |
| 42 | + taskExecutor.execute(() -> { | |
| 43 | + while (!taskQueue.isEmpty()) { | |
| 44 | + Message msg = taskQueue.poll(); | |
| 45 | + try { | |
| 46 | + JSONObject jsonObject = JSON.parseObject(msg.getBody()); | |
| 47 | + String app = jsonObject.getString("app"); | |
| 48 | + String stream = jsonObject.getString("stream"); | |
| 49 | + pushService.stop(app, stream); | |
| 50 | + | |
| 51 | + }catch (Exception e) { | |
| 52 | + logger.warn("[REDIS的关闭推流通知] 发现未处理的异常, \r\n{}", JSON.toJSONString(message)); | |
| 53 | + logger.error("[REDIS的关闭推流通知] 异常内容: ", e); | |
| 54 | + } | |
| 55 | + } | |
| 56 | + }); | |
| 57 | + } | |
| 58 | + } | |
| 59 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java
| ... | ... | @@ -289,7 +289,7 @@ public class RedisGbPlayMsgListener implements MessageListener { |
| 289 | 289 | // 添加订阅 |
| 290 | 290 | HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(content.getApp(), content.getStream(), true, "rtsp", mediaServerItem.getId()); |
| 291 | 291 | |
| 292 | - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{ | |
| 292 | + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam)->{ | |
| 293 | 293 | dynamicTask.stop(taskKey); |
| 294 | 294 | responseSendItem(mediaServerItem, content, toId, serial); |
| 295 | 295 | }); | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
| ... | ... | @@ -191,8 +191,6 @@ public interface IRedisCatchStorage { |
| 191 | 191 | |
| 192 | 192 | int getProxyStreamCount(String id); |
| 193 | 193 | |
| 194 | - int getGbReceiveCount(String id); | |
| 195 | - | |
| 196 | 194 | int getGbSendCount(String id); |
| 197 | 195 | |
| 198 | 196 | void addDiskInfo(List<Map<String, Object>> diskInfo); |
| ... | ... | @@ -204,4 +202,5 @@ public interface IRedisCatchStorage { |
| 204 | 202 | void removeAllDevice(); |
| 205 | 203 | |
| 206 | 204 | void sendDeviceOrChannelStatus(String deviceId, String channelId, boolean online); |
| 205 | + void sendChannelAddOrDelete(String deviceId, String channelId, boolean add); | |
| 207 | 206 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceAlarmMapper.java
| ... | ... | @@ -16,32 +16,32 @@ import java.util.List; |
| 16 | 16 | @Repository |
| 17 | 17 | public interface DeviceAlarmMapper { |
| 18 | 18 | |
| 19 | - @Insert("INSERT INTO device_alarm (deviceId, channelId, alarmPriority, alarmMethod, alarmTime, alarmDescription, longitude, latitude, alarmType , createTime ) " + | |
| 19 | + @Insert("INSERT INTO wvp_device_alarm (device_id, channel_id, alarm_priority, alarm_method, alarm_time, alarm_description, longitude, latitude, alarm_type , create_time ) " + | |
| 20 | 20 | "VALUES (#{deviceId}, #{channelId}, #{alarmPriority}, #{alarmMethod}, #{alarmTime}, #{alarmDescription}, #{longitude}, #{latitude}, #{alarmType}, #{createTime})") |
| 21 | 21 | int add(DeviceAlarm alarm); |
| 22 | 22 | |
| 23 | 23 | |
| 24 | 24 | @Select( value = {" <script>" + |
| 25 | - " SELECT * FROM device_alarm " + | |
| 25 | + " SELECT * FROM wvp_device_alarm " + | |
| 26 | 26 | " WHERE 1=1 " + |
| 27 | - " <if test=\"deviceId != null\" > AND deviceId = #{deviceId}</if>" + | |
| 28 | - " <if test=\"alarmPriority != null\" > AND alarmPriority = #{alarmPriority} </if>" + | |
| 29 | - " <if test=\"alarmMethod != null\" > AND alarmMethod = #{alarmMethod} </if>" + | |
| 30 | - " <if test=\"alarmType != null\" > AND alarmType = #{alarmType} </if>" + | |
| 31 | - " <if test=\"startTime != null\" > AND alarmTime >= #{startTime} </if>" + | |
| 32 | - " <if test=\"endTime != null\" > AND alarmTime <= #{endTime} </if>" + | |
| 33 | - " ORDER BY alarmTime ASC " + | |
| 27 | + " <if test=\"deviceId != null\" > AND device_id = #{deviceId}</if>" + | |
| 28 | + " <if test=\"alarmPriority != null\" > AND alarm_priority = #{alarmPriority} </if>" + | |
| 29 | + " <if test=\"alarmMethod != null\" > AND alarm_method = #{alarmMethod} </if>" + | |
| 30 | + " <if test=\"alarmType != null\" > AND alarm_type = #{alarmType} </if>" + | |
| 31 | + " <if test=\"startTime != null\" > AND alarm_time >= #{startTime} </if>" + | |
| 32 | + " <if test=\"endTime != null\" > AND alarm_time <= #{endTime} </if>" + | |
| 33 | + " ORDER BY alarm_time ASC " + | |
| 34 | 34 | " </script>"}) |
| 35 | 35 | List<DeviceAlarm> query(String deviceId, String alarmPriority, String alarmMethod, |
| 36 | 36 | String alarmType, String startTime, String endTime); |
| 37 | 37 | |
| 38 | 38 | |
| 39 | 39 | @Delete(" <script>" + |
| 40 | - "DELETE FROM device_alarm WHERE 1=1 " + | |
| 41 | - " <if test=\"deviceIdList != null and id == null \" > AND deviceId in " + | |
| 40 | + "DELETE FROM wvp_device_alarm WHERE 1=1 " + | |
| 41 | + " <if test=\"deviceIdList != null and id == null \" > AND device_id in " + | |
| 42 | 42 | "<foreach collection='deviceIdList' item='item' open='(' separator=',' close=')' > #{item}</foreach>" + |
| 43 | 43 | "</if>" + |
| 44 | - " <if test=\"time != null and id == null \" > AND alarmTime <= #{time}</if>" + | |
| 44 | + " <if test=\"time != null and id == null \" > AND alarm_time <= #{time}</if>" + | |
| 45 | 45 | " <if test=\"id != null\" > AND id = #{id}</if>" + |
| 46 | 46 | " </script>" |
| 47 | 47 | ) | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
| ... | ... | @@ -3,7 +3,6 @@ package com.genersoft.iot.vmp.storager.dao; |
| 3 | 3 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 4 | 4 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 5 | 5 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannelInPlatform; |
| 6 | -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; | |
| 7 | 6 | import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; |
| 8 | 7 | import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend; |
| 9 | 8 | import org.apache.ibatis.annotations.*; |
| ... | ... | @@ -18,10 +17,10 @@ import java.util.List; |
| 18 | 17 | @Repository |
| 19 | 18 | public interface DeviceChannelMapper { |
| 20 | 19 | |
| 21 | - @Insert("INSERT INTO device_channel (channelId, deviceId, name, manufacture, model, owner, civilCode, block, " + | |
| 22 | - "address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " + | |
| 23 | - "ipAddress, port, password, PTZType, status, streamId, longitude, latitude, longitudeGcj02, latitudeGcj02, " + | |
| 24 | - "longitudeWgs84, latitudeWgs84, hasAudio, createTime, updateTime, businessGroupId, gpsTime) " + | |
| 20 | + @Insert("INSERT INTO wvp_device_channel (channel_id, device_id, name, manufacture, model, owner, civil_code, block, " + | |
| 21 | + "address, parental, parent_id, safety_way, register_way, cert_num, certifiable, err_code, secrecy, " + | |
| 22 | + "ip_address, port, password, ptz_type, status, stream_id, longitude, latitude, longitude_gcj02, latitude_gcj02, " + | |
| 23 | + "longitude_wgs84, latitude_wgs84, has_audio, create_time, update_time, business_group_id, gps_time) " + | |
| 25 | 24 | "VALUES (#{channelId}, #{deviceId}, #{name}, #{manufacture}, #{model}, #{owner}, #{civilCode}, #{block}," + |
| 26 | 25 | "#{address}, #{parental}, #{parentId}, #{safetyWay}, #{registerWay}, #{certNum}, #{certifiable}, #{errCode}, #{secrecy}, " + |
| 27 | 26 | "#{ipAddress}, #{port}, #{password}, #{PTZType}, #{status}, #{streamId}, #{longitude}, #{latitude}, #{longitudeGcj02}, " + |
| ... | ... | @@ -29,39 +28,39 @@ public interface DeviceChannelMapper { |
| 29 | 28 | int add(DeviceChannel channel); |
| 30 | 29 | |
| 31 | 30 | @Update(value = {" <script>" + |
| 32 | - "UPDATE device_channel " + | |
| 33 | - "SET updateTime=#{updateTime}" + | |
| 31 | + "UPDATE wvp_device_channel " + | |
| 32 | + "SET update_time=#{updateTime}" + | |
| 34 | 33 | "<if test='name != null'>, name=#{name}</if>" + |
| 35 | 34 | "<if test='manufacture != null'>, manufacture=#{manufacture}</if>" + |
| 36 | 35 | "<if test='model != null'>, model=#{model}</if>" + |
| 37 | 36 | "<if test='owner != null'>, owner=#{owner}</if>" + |
| 38 | - "<if test='civilCode != null'>, civilCode=#{civilCode}</if>" + | |
| 37 | + "<if test='civilCode != null'>, civil_code=#{civilCode}</if>" + | |
| 39 | 38 | "<if test='block != null'>, block=#{block}</if>" + |
| 40 | 39 | "<if test='address != null'>, address=#{address}</if>" + |
| 41 | 40 | "<if test='parental != null'>, parental=#{parental}</if>" + |
| 42 | - "<if test='parentId != null'>, parentId=#{parentId}</if>" + | |
| 43 | - "<if test='safetyWay != null'>, safetyWay=#{safetyWay}</if>" + | |
| 44 | - "<if test='registerWay != null'>, registerWay=#{registerWay}</if>" + | |
| 45 | - "<if test='certNum != null'>, certNum=#{certNum}</if>" + | |
| 41 | + "<if test='parentId != null'>, parent_id=#{parentId}</if>" + | |
| 42 | + "<if test='safetyWay != null'>, safety_way=#{safetyWay}</if>" + | |
| 43 | + "<if test='registerWay != null'>, register_way=#{registerWay}</if>" + | |
| 44 | + "<if test='certNum != null'>, cert_num=#{certNum}</if>" + | |
| 46 | 45 | "<if test='certifiable != null'>, certifiable=#{certifiable}</if>" + |
| 47 | - "<if test='errCode != null'>, errCode=#{errCode}</if>" + | |
| 46 | + "<if test='errCode != null'>, err_code=#{errCode}</if>" + | |
| 48 | 47 | "<if test='secrecy != null'>, secrecy=#{secrecy}</if>" + |
| 49 | - "<if test='ipAddress != null'>, ipAddress=#{ipAddress}</if>" + | |
| 48 | + "<if test='ipAddress != null'>, ip_address=#{ipAddress}</if>" + | |
| 50 | 49 | "<if test='port != null'>, port=#{port}</if>" + |
| 51 | 50 | "<if test='password != null'>, password=#{password}</if>" + |
| 52 | - "<if test='PTZType != null'>, PTZType=#{PTZType}</if>" + | |
| 51 | + "<if test='PTZType != null'>, ptz_type=#{PTZType}</if>" + | |
| 53 | 52 | "<if test='status != null'>, status=#{status}</if>" + |
| 54 | - "<if test='streamId != null'>, streamId=#{streamId}</if>" + | |
| 55 | - "<if test='hasAudio != null'>, hasAudio=#{hasAudio}</if>" + | |
| 53 | + "<if test='streamId != null'>, stream_id=#{streamId}</if>" + | |
| 54 | + "<if test='hasAudio != null'>, has_audio=#{hasAudio}</if>" + | |
| 56 | 55 | "<if test='longitude != null'>, longitude=#{longitude}</if>" + |
| 57 | 56 | "<if test='latitude != null'>, latitude=#{latitude}</if>" + |
| 58 | - "<if test='longitudeGcj02 != null'>, longitudeGcj02=#{longitudeGcj02}</if>" + | |
| 59 | - "<if test='latitudeGcj02 != null'>, latitudeGcj02=#{latitudeGcj02}</if>" + | |
| 60 | - "<if test='longitudeWgs84 != null'>, longitudeWgs84=#{longitudeWgs84}</if>" + | |
| 61 | - "<if test='latitudeWgs84 != null'>, latitudeWgs84=#{latitudeWgs84}</if>" + | |
| 62 | - "<if test='businessGroupId != null'>, businessGroupId=#{businessGroupId}</if>" + | |
| 63 | - "<if test='gpsTime != null'>, gpsTime=#{gpsTime}</if>" + | |
| 64 | - "WHERE deviceId=#{deviceId} AND channelId=#{channelId}"+ | |
| 57 | + "<if test='longitudeGcj02 != null'>, longitude_gcj02=#{longitudeGcj02}</if>" + | |
| 58 | + "<if test='latitudeGcj02 != null'>, latitude_gcj02=#{latitudeGcj02}</if>" + | |
| 59 | + "<if test='longitudeWgs84 != null'>, longitude_wgs84=#{longitudeWgs84}</if>" + | |
| 60 | + "<if test='latitudeWgs84 != null'>, latitude_wgs84=#{latitudeWgs84}</if>" + | |
| 61 | + "<if test='businessGroupId != null'>, business_group_id=#{businessGroupId}</if>" + | |
| 62 | + "<if test='gpsTime != null'>, gps_time=#{gpsTime}</if>" + | |
| 63 | + "WHERE device_id=#{deviceId} AND channel_id=#{channelId}"+ | |
| 65 | 64 | " </script>"}) |
| 66 | 65 | int update(DeviceChannel channel); |
| 67 | 66 | |
| ... | ... | @@ -69,42 +68,42 @@ public interface DeviceChannelMapper { |
| 69 | 68 | "SELECT " + |
| 70 | 69 | "dc.* " + |
| 71 | 70 | "from " + |
| 72 | - "device_channel dc " + | |
| 71 | + "wvp_device_channel dc " + | |
| 73 | 72 | "WHERE " + |
| 74 | - "dc.deviceId = #{deviceId} " + | |
| 75 | -" <if test='query != null'> AND (dc.channelId LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%'))</if> " + | |
| 76 | - " <if test='parentChannelId != null'> AND (dc.parentId=#{parentChannelId} OR dc.civilCode = #{parentChannelId}) </if> " + | |
| 77 | - " <if test='online == true' > AND dc.status=1</if>" + | |
| 78 | - " <if test='online == false' > AND dc.status=0</if>" + | |
| 79 | - " <if test='hasSubChannel == true' > AND dc.subCount > 0 </if>" + | |
| 80 | - " <if test='hasSubChannel == false' > AND dc.subCount = 0 </if>" + | |
| 81 | - "<if test='channelIds != null'> AND dc.channelId in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" + | |
| 73 | + "dc.device_id = #{deviceId} " + | |
| 74 | +" <if test='query != null'> AND (dc.channel_id LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%'))</if> " + | |
| 75 | + " <if test='parentChannelId != null'> AND (dc.parent_id=#{parentChannelId} OR dc.civil_code = #{parentChannelId}) </if> " + | |
| 76 | + " <if test='online == true' > AND dc.status= true</if>" + | |
| 77 | + " <if test='online == false' > AND dc.status= false</if>" + | |
| 78 | + " <if test='hasSubChannel == true' > AND dc.sub_count > 0 </if>" + | |
| 79 | + " <if test='hasSubChannel == false' > AND dc.sub_count = 0 </if>" + | |
| 80 | + "<if test='channelIds != null'> AND dc.channel_id in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" + | |
| 82 | 81 | "#{item} " + |
| 83 | 82 | "</foreach> </if>" + |
| 84 | - "ORDER BY dc.channelId " + | |
| 83 | + "ORDER BY dc.channel_id " + | |
| 85 | 84 | " </script>"}) |
| 86 | 85 | List<DeviceChannel> queryChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online, List<String> channelIds); |
| 87 | 86 | |
| 88 | 87 | @Select(value = {" <script>" + |
| 89 | 88 | "SELECT " + |
| 90 | 89 | "dc.*, " + |
| 91 | - "de.name as deviceName, " + | |
| 92 | - "de.online as deviceOnline " + | |
| 90 | + "de.name as device_name, " + | |
| 91 | + "de.on_line as device_online " + | |
| 93 | 92 | "from " + |
| 94 | - "device_channel dc " + | |
| 95 | - "LEFT JOIN device de ON dc.deviceId = de.deviceId " + | |
| 93 | + "wvp_device_channel dc " + | |
| 94 | + "LEFT JOIN wvp_device de ON dc.device_id = de.device_id " + | |
| 96 | 95 | "WHERE 1=1" + |
| 97 | - " <if test='deviceId != null'> AND dc.deviceId = #{deviceId} </if> " + | |
| 98 | - " <if test='query != null'> AND (dc.channelId LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " + | |
| 99 | - " <if test='parentChannelId != null'> AND dc.parentId=#{parentChannelId} </if> " + | |
| 100 | - " <if test='online == true' > AND dc.status=1</if>" + | |
| 101 | - " <if test='online == false' > AND dc.status=0</if>" + | |
| 102 | - " <if test='hasSubChannel == true' > AND dc.subCount > 0 </if>" + | |
| 103 | - " <if test='hasSubChannel == false' > AND dc.subCount = 0 </if>" + | |
| 104 | - "<if test='channelIds != null'> AND dc.channelId in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" + | |
| 96 | + " <if test='deviceId != null'> AND dc.device_id = #{deviceId} </if> " + | |
| 97 | + " <if test='query != null'> AND (dc.channel_id LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " + | |
| 98 | + " <if test='parentChannelId != null'> AND dc.parent_id=#{parentChannelId} </if> " + | |
| 99 | + " <if test='online == true' > AND dc.status=true</if>" + | |
| 100 | + " <if test='online == false' > AND dc.status=false</if>" + | |
| 101 | + " <if test='hasSubChannel == true' > AND dc.sub_count > 0 </if>" + | |
| 102 | + " <if test='hasSubChannel == false' > AND dc.sub_count = 0 </if>" + | |
| 103 | + "<if test='channelIds != null'> AND dc.channel_id in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" + | |
| 105 | 104 | "#{item} " + |
| 106 | 105 | "</foreach> </if>" + |
| 107 | - "ORDER BY dc.channelId ASC" + | |
| 106 | + "ORDER BY dc.channel_id ASC" + | |
| 108 | 107 | " </script>"}) |
| 109 | 108 | List<DeviceChannelExtend> queryChannelsWithDeviceInfo(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online, List<String> channelIds); |
| 110 | 109 | |
| ... | ... | @@ -112,151 +111,97 @@ public interface DeviceChannelMapper { |
| 112 | 111 | @Select(value = {" <script>" + |
| 113 | 112 | "SELECT " + |
| 114 | 113 | "dc.*, " + |
| 115 | - "de.name as deviceName, " + | |
| 116 | - "de.online as deviceOnline " + | |
| 114 | + "de.name as device_name, " + | |
| 115 | + "de.on_line as device_online " + | |
| 117 | 116 | "from " + |
| 118 | - "device_channel dc " + | |
| 119 | - "LEFT JOIN device de ON dc.deviceId = de.deviceId " + | |
| 117 | + "wvp_device_channel dc " + | |
| 118 | + "LEFT JOIN wvp_device de ON dc.device_id = de.device_id " + | |
| 120 | 119 | "WHERE 1=1" + |
| 121 | - " <if test='deviceId != null'> AND dc.deviceId = #{deviceId} </if> " + | |
| 122 | - " <if test='query != null'> AND (dc.channelId LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " + | |
| 123 | - " <if test='parentChannelId != null'> AND dc.parentId=#{parentChannelId} </if> " + | |
| 124 | - " <if test='online == true' > AND dc.status=1</if>" + | |
| 125 | - " <if test='online == false' > AND dc.status=0</if>" + | |
| 126 | - " <if test='hasSubChannel == true' > AND dc.subCount > 0 </if>" + | |
| 127 | - " <if test='hasSubChannel == false' > AND dc.subCount = 0 </if>" + | |
| 128 | - "<if test='channelIds != null'> AND dc.channelId in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" + | |
| 120 | + " <if test='deviceId != null'> AND dc.device_id = #{deviceId} </if> " + | |
| 121 | + " <if test='query != null'> AND (dc.channel_id LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " + | |
| 122 | + " <if test='parentChannelId != null'> AND dc.parent_id=#{parentChannelId} </if> " + | |
| 123 | + " <if test='online == true' > AND dc.status=true</if>" + | |
| 124 | + " <if test='online == false' > AND dc.status=false</if>" + | |
| 125 | + " <if test='hasSubChannel == true' > AND dc.sub_count > 0 </if>" + | |
| 126 | + " <if test='hasSubChannel == false' > AND dc.sub_count = 0 </if>" + | |
| 127 | + "<if test='channelIds != null'> AND dc.channel_id in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" + | |
| 129 | 128 | "#{item} " + |
| 130 | 129 | "</foreach> </if>" + |
| 131 | - "ORDER BY dc.channelId ASC " + | |
| 130 | + "ORDER BY dc.channel_id ASC " + | |
| 132 | 131 | "Limit #{limit} OFFSET #{start}" + |
| 133 | 132 | " </script>"}) |
| 134 | 133 | List<DeviceChannelExtend> queryChannelsByDeviceIdWithStartAndLimit(String deviceId,List<String> channelIds, String parentChannelId, String query, |
| 135 | 134 | Boolean hasSubChannel, Boolean online, int start, int limit); |
| 136 | 135 | |
| 137 | - @Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND channelId=#{channelId}") | |
| 136 | + @Select("SELECT * FROM wvp_device_channel WHERE device_id=#{deviceId} AND channel_id=#{channelId}") | |
| 138 | 137 | DeviceChannel queryChannel(String deviceId, String channelId); |
| 139 | 138 | |
| 140 | - @Delete("DELETE FROM device_channel WHERE deviceId=#{deviceId}") | |
| 139 | + @Delete("DELETE FROM wvp_device_channel WHERE device_id=#{deviceId}") | |
| 141 | 140 | int cleanChannelsByDeviceId(String deviceId); |
| 142 | 141 | |
| 143 | - @Delete("DELETE FROM device_channel WHERE deviceId=#{deviceId} AND channelId=#{channelId}") | |
| 142 | + @Delete("DELETE FROM wvp_device_channel WHERE device_id=#{deviceId} AND channel_id=#{channelId}") | |
| 144 | 143 | int del(String deviceId, String channelId); |
| 145 | 144 | |
| 146 | - @Update(value = {"UPDATE device_channel SET streamId=null WHERE deviceId=#{deviceId} AND channelId=#{channelId}"}) | |
| 145 | + @Update(value = {"UPDATE wvp_device_channel SET stream_id=null WHERE device_id=#{deviceId} AND channel_id=#{channelId}"}) | |
| 147 | 146 | void stopPlay(String deviceId, String channelId); |
| 148 | 147 | |
| 149 | - @Update(value = {"UPDATE device_channel SET streamId=#{streamId} WHERE deviceId=#{deviceId} AND channelId=#{channelId}"}) | |
| 148 | + @Update(value = {"UPDATE wvp_device_channel SET stream_id=#{streamId} WHERE device_id=#{deviceId} AND channel_id=#{channelId}"}) | |
| 150 | 149 | void startPlay(String deviceId, String channelId, String streamId); |
| 151 | 150 | |
| 152 | 151 | @Select(value = {" <script>" + |
| 153 | 152 | "SELECT " + |
| 154 | 153 | " dc.id,\n" + |
| 155 | - " dc.channelId,\n" + | |
| 156 | - " dc.deviceId,\n" + | |
| 154 | + " dc.channel_id,\n" + | |
| 155 | + " dc.device_id,\n" + | |
| 157 | 156 | " dc.name,\n" + |
| 158 | 157 | " de.manufacturer,\n" + |
| 159 | - " de.hostAddress,\n" + | |
| 160 | - " dc.subCount,\n" + | |
| 161 | - " pgc.platformId as platformId,\n" + | |
| 162 | - " pgc.catalogId as catalogId " + | |
| 163 | - " FROM device_channel dc " + | |
| 164 | - " LEFT JOIN device de ON dc.deviceId = de.deviceId " + | |
| 165 | - " LEFT JOIN platform_gb_channel pgc on pgc.deviceChannelId = dc.id " + | |
| 158 | + " de.host_address,\n" + | |
| 159 | + " dc.sub_count,\n" + | |
| 160 | + " pgc.platform_id as platform_id,\n" + | |
| 161 | + " pgc.catalog_id as catalog_id " + | |
| 162 | + " FROM wvp_device_channel dc " + | |
| 163 | + " LEFT JOIN wvp_device de ON dc.device_id = de.device_id " + | |
| 164 | + " LEFT JOIN wvp_platform_gb_channel pgc on pgc.device_channel_id = dc.id " + | |
| 166 | 165 | " WHERE 1=1 " + |
| 167 | - " <if test='query != null'> AND (dc.channelId LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%'))</if> " + | |
| 168 | - " <if test='online == true' > AND dc.status=1</if> " + | |
| 169 | - " <if test='online == false' > AND dc.status=0</if> " + | |
| 170 | - " <if test='hasSubChannel!= null and hasSubChannel == true' > AND dc.subCount > 0</if> " + | |
| 171 | - " <if test='hasSubChannel!= null and hasSubChannel == false' > AND dc.subCount = 0</if> " + | |
| 172 | - " <if test='catalogId == null ' > AND dc.id not in (select deviceChannelId from platform_gb_channel where platformId=#{platformId} ) </if> " + | |
| 173 | - " <if test='catalogId != null ' > AND pgc.platformId = #{platformId} and pgc.catalogId=#{catalogId} </if> " + | |
| 174 | - " ORDER BY dc.deviceId, dc.channelId ASC" + | |
| 166 | + " <if test='query != null'> AND (dc.channel_id LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%'))</if> " + | |
| 167 | + " <if test='online == true' > AND dc.status=true</if> " + | |
| 168 | + " <if test='online == false' > AND dc.status=false</if> " + | |
| 169 | + " <if test='hasSubChannel!= null and has_sub_channel == true' > AND dc.sub_count > 0</if> " + | |
| 170 | + " <if test='hasSubChannel!= null and has_sub_channel == false' > AND dc.sub_count = 0</if> " + | |
| 171 | + " <if test='catalogId == null ' > AND dc.id not in (select device_channel_id from wvp_platform_gb_channel where platform_id=#{platformId} ) </if> " + | |
| 172 | + " <if test='catalogId != null ' > AND pgc.platform_id = #{platformId} and pgc.catalog_id=#{catalogId} </if> " + | |
| 173 | + " ORDER BY dc.device_id, dc.channel_id ASC" + | |
| 175 | 174 | " </script>"}) |
| 176 | 175 | List<ChannelReduce> queryChannelListInAll(String query, Boolean online, Boolean hasSubChannel, String platformId, String catalogId); |
| 177 | 176 | |
| 178 | 177 | @Select(value = {" <script>" + |
| 179 | 178 | "SELECT " + |
| 180 | 179 | " dc.*,\n" + |
| 181 | - " pgc.platformId as platformId,\n" + | |
| 182 | - " pgc.catalogId as catalogId " + | |
| 183 | - " FROM device_channel dc " + | |
| 184 | - " LEFT JOIN platform_gb_channel pgc on pgc.deviceChannelId = dc.id " + | |
| 185 | - " WHERE pgc.platformId = #{platformId} " + | |
| 186 | - " ORDER BY dc.deviceId, dc.channelId ASC" + | |
| 180 | + " pgc.platform_id as platform_id,\n" + | |
| 181 | + " pgc.catalog_id as catalog_id " + | |
| 182 | + " FROM wvp_device_channel dc " + | |
| 183 | + " LEFT JOIN wvp_platform_gb_channel pgc on pgc.device_channel_id = dc.id " + | |
| 184 | + " WHERE pgc.platform_id = #{platformId} " + | |
| 185 | + " ORDER BY dc.device_id, dc.channel_id ASC" + | |
| 187 | 186 | " </script>"}) |
| 188 | 187 | List<DeviceChannelInPlatform> queryChannelByPlatformId(String platformId); |
| 189 | 188 | |
| 190 | 189 | |
| 191 | - @Select("SELECT * FROM device_channel WHERE channelId=#{channelId}") | |
| 190 | + @Select("SELECT * FROM wvp_device_channel WHERE channel_id=#{channelId}") | |
| 192 | 191 | List<DeviceChannel> queryChannelByChannelId( String channelId); |
| 193 | 192 | |
| 194 | - @Update(value = {"UPDATE device_channel SET status=0 WHERE deviceId=#{deviceId} AND channelId=#{channelId}"}) | |
| 193 | + @Update(value = {"UPDATE wvp_device_channel SET status=false WHERE device_id=#{deviceId} AND channel_id=#{channelId}"}) | |
| 195 | 194 | void offline(String deviceId, String channelId); |
| 196 | 195 | |
| 197 | - @Update(value = {"UPDATE device_channel SET status=0 WHERE deviceId=#{deviceId}"}) | |
| 196 | + @Update(value = {"UPDATE wvp_device_channel SET status=fasle WHERE device_id=#{deviceId}"}) | |
| 198 | 197 | void offlineByDeviceId(String deviceId); |
| 199 | 198 | |
| 200 | -// @Insert("<script> " + | |
| 201 | -// "insert into device_channel " + | |
| 202 | -// "(channelId, deviceId, name, manufacture, model, owner, civilCode, block, subCount, " + | |
| 203 | -// " address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " + | |
| 204 | -// " ipAddress, port, password, PTZType, status, streamId, longitude, latitude, longitudeGcj02, latitudeGcj02, " + | |
| 205 | -// " longitudeWgs84, latitudeWgs84, hasAudio, createTime, updateTime, businessGroupId, gpsTime) " + | |
| 206 | -// "values " + | |
| 207 | -// "<foreach collection='addChannels' index='index' item='item' separator=','> " + | |
| 208 | -// "(#{item.channelId}, #{item.deviceId}, #{item.name}, #{item.manufacture}, #{item.model}, " + | |
| 209 | -// "#{item.owner}, #{item.civilCode}, #{item.block},#{item.subCount}," + | |
| 210 | -// "#{item.address}, #{item.parental}, #{item.parentId}, #{item.safetyWay}, #{item.registerWay}, " + | |
| 211 | -// "#{item.certNum}, #{item.certifiable}, #{item.errCode}, #{item.secrecy}, " + | |
| 212 | -// "#{item.ipAddress}, #{item.port}, #{item.password}, #{item.PTZType}, #{item.status}, " + | |
| 213 | -// "#{item.streamId}, #{item.longitude}, #{item.latitude},#{item.longitudeGcj02}, " + | |
| 214 | -// "#{item.latitudeGcj02},#{item.longitudeWgs84}, #{item.latitudeWgs84}, #{item.hasAudio}, now(), now(), " + | |
| 215 | -// "#{item.businessGroupId}, #{item.gpsTime}) " + | |
| 216 | -// "</foreach> " + | |
| 217 | -// "ON DUPLICATE KEY UPDATE " + | |
| 218 | -// "updateTime=VALUES(updateTime), " + | |
| 219 | -// "name=VALUES(name), " + | |
| 220 | -// "manufacture=VALUES(manufacture), " + | |
| 221 | -// "model=VALUES(model), " + | |
| 222 | -// "owner=VALUES(owner), " + | |
| 223 | -// "civilCode=VALUES(civilCode), " + | |
| 224 | -// "block=VALUES(block), " + | |
| 225 | -// "subCount=VALUES(subCount), " + | |
| 226 | -// "address=VALUES(address), " + | |
| 227 | -// "parental=VALUES(parental), " + | |
| 228 | -// "parentId=VALUES(parentId), " + | |
| 229 | -// "safetyWay=VALUES(safetyWay), " + | |
| 230 | -// "registerWay=VALUES(registerWay), " + | |
| 231 | -// "certNum=VALUES(certNum), " + | |
| 232 | -// "certifiable=VALUES(certifiable), " + | |
| 233 | -// "errCode=VALUES(errCode), " + | |
| 234 | -// "secrecy=VALUES(secrecy), " + | |
| 235 | -// "ipAddress=VALUES(ipAddress), " + | |
| 236 | -// "port=VALUES(port), " + | |
| 237 | -// "password=VALUES(password), " + | |
| 238 | -// "PTZType=VALUES(PTZType), " + | |
| 239 | -// "status=VALUES(status), " + | |
| 240 | -// "streamId=VALUES(streamId), " + | |
| 241 | -// "longitude=VALUES(longitude), " + | |
| 242 | -// "latitude=VALUES(latitude), " + | |
| 243 | -// "longitudeGcj02=VALUES(longitudeGcj02), " + | |
| 244 | -// "latitudeGcj02=VALUES(latitudeGcj02), " + | |
| 245 | -// "longitudeWgs84=VALUES(longitudeWgs84), " + | |
| 246 | -// "latitudeWgs84=VALUES(latitudeWgs84), " + | |
| 247 | -// "hasAudio=VALUES(hasAudio), " + | |
| 248 | -// "businessGroupId=VALUES(businessGroupId), " + | |
| 249 | -// "gpsTime=VALUES(gpsTime)" + | |
| 250 | -// "</script>") | |
| 251 | -// int batchAdd(List<DeviceChannel> addChannels); | |
| 252 | - | |
| 253 | - | |
| 254 | 199 | @Insert("<script> " + |
| 255 | - "insert into device_channel " + | |
| 256 | - "(channelId, deviceId, name, manufacture, model, owner, civilCode, block, subCount, " + | |
| 257 | - " address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " + | |
| 258 | - " ipAddress, port, password, PTZType, status, streamId, longitude, latitude, longitudeGcj02, latitudeGcj02, " + | |
| 259 | - " longitudeWgs84, latitudeWgs84, hasAudio, createTime, updateTime, businessGroupId, gpsTime) " + | |
| 200 | + "insert into wvp_device_channel " + | |
| 201 | + "(channel_id, device_id, name, manufacture, model, owner, civil_code, block, sub_count, " + | |
| 202 | + " address, parental, parent_id, safety_way, register_way, cert_num, certifiable, err_code, secrecy, " + | |
| 203 | + " ip_address,port,password,ptz_type,status,stream_id,longitude,latitude,longitude_gcj02,latitude_gcj02,"+ | |
| 204 | + " longitude_wgs84,latitude_wgs84,has_audio,create_time,update_time,business_group_id,gps_time)"+ | |
| 260 | 205 | "values " + |
| 261 | 206 | "<foreach collection='addChannels' index='index' item='item' separator=','> " + |
| 262 | 207 | "(#{item.channelId}, #{item.deviceId}, #{item.name}, #{item.manufacture}, #{item.model}, " + |
| ... | ... | @@ -273,11 +218,11 @@ public interface DeviceChannelMapper { |
| 273 | 218 | |
| 274 | 219 | |
| 275 | 220 | @Insert("<script> " + |
| 276 | - "insert into device_channel " + | |
| 277 | - "(channelId, deviceId, name, manufacture, model, owner, civilCode, block, subCount, " + | |
| 278 | - " address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " + | |
| 279 | - " ipAddress, port, password, PTZType, status, streamId, longitude, latitude, longitudeGcj02, latitudeGcj02, " + | |
| 280 | - " longitudeWgs84, latitudeWgs84, hasAudio, createTime, updateTime, businessGroupId, gpsTime) " + | |
| 221 | + "insert into wvp_device_channel " + | |
| 222 | + "(channel_id,device_id,name,manufacture,model,owner,civil_code,block,sub_count,"+ | |
| 223 | + " address,parental,parent_id,safety_way,register_way,cert_num,certifiable,err_code,secrecy,"+ | |
| 224 | + " ip_address,port,password,ptz_type,status,stream_id,longitude,latitude,longitude_gcj02,latitude_gcj02,"+ | |
| 225 | + " longitude_wgs84,latitude_wgs84,has_audio,create_time,update_time,business_group_id,gps_time)"+ | |
| 281 | 226 | "values " + |
| 282 | 227 | "<foreach collection='addChannels' index='index' item='item' separator=','> " + |
| 283 | 228 | "(#{item.channelId}, #{item.deviceId}, #{item.name}, #{item.manufacture}, #{item.model}, " + |
| ... | ... | @@ -290,215 +235,234 @@ public interface DeviceChannelMapper { |
| 290 | 235 | "#{item.businessGroupId}, #{item.gpsTime}) " + |
| 291 | 236 | "</foreach> " + |
| 292 | 237 | "ON DUPLICATE KEY UPDATE " + |
| 293 | - "updateTime=VALUES(updateTime), " + | |
| 238 | + "update_time=VALUES(update_time), " + | |
| 294 | 239 | "name=VALUES(name), " + |
| 295 | 240 | "manufacture=VALUES(manufacture), " + |
| 296 | 241 | "model=VALUES(model), " + |
| 297 | 242 | "owner=VALUES(owner), " + |
| 298 | - "civilCode=VALUES(civilCode), " + | |
| 243 | + "civil_code=VALUES(civil_code), " + | |
| 299 | 244 | "block=VALUES(block), " + |
| 300 | - "subCount=VALUES(subCount), " + | |
| 245 | + "sub_count=VALUES(sub_count), " + | |
| 301 | 246 | "address=VALUES(address), " + |
| 302 | 247 | "parental=VALUES(parental), " + |
| 303 | - "parentId=VALUES(parentId), " + | |
| 304 | - "safetyWay=VALUES(safetyWay), " + | |
| 305 | - "registerWay=VALUES(registerWay), " + | |
| 306 | - "certNum=VALUES(certNum), " + | |
| 248 | + "parent_id=VALUES(parent_id), " + | |
| 249 | + "safety_way=VALUES(safety_way), " + | |
| 250 | + "register_way=VALUES(register_way), " + | |
| 251 | + "cert_num=VALUES(cert_num), " + | |
| 307 | 252 | "certifiable=VALUES(certifiable), " + |
| 308 | - "errCode=VALUES(errCode), " + | |
| 253 | + "err_code=VALUES(err_code), " + | |
| 309 | 254 | "secrecy=VALUES(secrecy), " + |
| 310 | - "ipAddress=VALUES(ipAddress), " + | |
| 255 | + "ip_address=VALUES(ip_address), " + | |
| 311 | 256 | "port=VALUES(port), " + |
| 312 | 257 | "password=VALUES(password), " + |
| 313 | - "PTZType=VALUES(PTZType), " + | |
| 258 | + "ptz_type=VALUES(ptz_type), " + | |
| 314 | 259 | "status=VALUES(status), " + |
| 315 | - "streamId=VALUES(streamId), " + | |
| 260 | + "stream_id=VALUES(stream_id), " + | |
| 316 | 261 | "longitude=VALUES(longitude), " + |
| 317 | 262 | "latitude=VALUES(latitude), " + |
| 318 | - "longitudeGcj02=VALUES(longitudeGcj02), " + | |
| 319 | - "latitudeGcj02=VALUES(latitudeGcj02), " + | |
| 320 | - "longitudeWgs84=VALUES(longitudeWgs84), " + | |
| 321 | - "latitudeWgs84=VALUES(latitudeWgs84), " + | |
| 322 | - "hasAudio=VALUES(hasAudio), " + | |
| 323 | - "businessGroupId=VALUES(businessGroupId), " + | |
| 324 | - "gpsTime=VALUES(gpsTime)" + | |
| 263 | + "longitude_gcj02=VALUES(longitude_gcj02), " + | |
| 264 | + "latitude_gcj02=VALUES(latitude_gcj02), " + | |
| 265 | + "longitude_wgs84=VALUES(longitude_wgs84), " + | |
| 266 | + "latitude_wgs84=VALUES(latitude_wgs84), " + | |
| 267 | + "has_audio=VALUES(has_audio), " + | |
| 268 | + "business_group_id=VALUES(business_group_id), " + | |
| 269 | + "gps_time=VALUES(gps_time)" + | |
| 325 | 270 | "</script>") |
| 326 | 271 | int batchAddOrUpdate(List<DeviceChannel> addChannels); |
| 327 | 272 | |
| 328 | - @Update(value = {"UPDATE device_channel SET status=1 WHERE deviceId=#{deviceId} AND channelId=#{channelId}"}) | |
| 273 | + @Update(value = {"UPDATE wvp_device_channel SET status=true WHERE device_id=#{deviceId} AND channel_id=#{channelId}"}) | |
| 329 | 274 | void online(String deviceId, String channelId); |
| 330 | 275 | |
| 331 | 276 | @Update({"<script>" + |
| 332 | 277 | "<foreach collection='updateChannels' item='item' separator=';'>" + |
| 333 | 278 | " UPDATE" + |
| 334 | - " device_channel" + | |
| 335 | - " SET updateTime=#{item.updateTime}" + | |
| 279 | + " wvp_device_channel" + | |
| 280 | + " SET update_time=#{item.updateTime}" + | |
| 336 | 281 | "<if test='item.name != null'>, name=#{item.name}</if>" + |
| 337 | 282 | "<if test='item.manufacture != null'>, manufacture=#{item.manufacture}</if>" + |
| 338 | 283 | "<if test='item.model != null'>, model=#{item.model}</if>" + |
| 339 | 284 | "<if test='item.owner != null'>, owner=#{item.owner}</if>" + |
| 340 | - "<if test='item.civilCode != null'>, civilCode=#{item.civilCode}</if>" + | |
| 285 | + "<if test='item.civilCode != null'>, civil_code=#{item.civilCode}</if>" + | |
| 341 | 286 | "<if test='item.block != null'>, block=#{item.block}</if>" + |
| 342 | - "<if test='item.subCount != null'>, subCount=#{item.subCount}</if>" + | |
| 287 | + "<if test='item.subCount != null'>, sub_count=#{item.subCount}</if>" + | |
| 343 | 288 | "<if test='item.address != null'>, address=#{item.address}</if>" + |
| 344 | 289 | "<if test='item.parental != null'>, parental=#{item.parental}</if>" + |
| 345 | - "<if test='item.parentId != null'>, parentId=#{item.parentId}</if>" + | |
| 346 | - "<if test='item.safetyWay != null'>, safetyWay=#{item.safetyWay}</if>" + | |
| 347 | - "<if test='item.registerWay != null'>, registerWay=#{item.registerWay}</if>" + | |
| 348 | - "<if test='item.certNum != null'>, certNum=#{item.certNum}</if>" + | |
| 290 | + "<if test='item.parentId != null'>, parent_id=#{item.parentId}</if>" + | |
| 291 | + "<if test='item.safetyWay != null'>, safety_way=#{item.safetyWay}</if>" + | |
| 292 | + "<if test='item.registerWay != null'>, register_way=#{item.registerWay}</if>" + | |
| 293 | + "<if test='item.certNum != null'>, cert_num=#{item.certNum}</if>" + | |
| 349 | 294 | "<if test='item.certifiable != null'>, certifiable=#{item.certifiable}</if>" + |
| 350 | - "<if test='item.errCode != null'>, errCode=#{item.errCode}</if>" + | |
| 295 | + "<if test='item.errCode != null'>, err_code=#{item.errCode}</if>" + | |
| 351 | 296 | "<if test='item.secrecy != null'>, secrecy=#{item.secrecy}</if>" + |
| 352 | - "<if test='item.ipAddress != null'>, ipAddress=#{item.ipAddress}</if>" + | |
| 297 | + "<if test='item.ipAddress != null'>, ip_address=#{item.ipAddress}</if>" + | |
| 353 | 298 | "<if test='item.port != null'>, port=#{item.port}</if>" + |
| 354 | 299 | "<if test='item.password != null'>, password=#{item.password}</if>" + |
| 355 | - "<if test='item.PTZType != null'>, PTZType=#{item.PTZType}</if>" + | |
| 300 | + "<if test='item.PTZType != null'>, ptz_type=#{item.PTZType}</if>" + | |
| 356 | 301 | "<if test='item.status != null'>, status=#{item.status}</if>" + |
| 357 | - "<if test='item.streamId != null'>, streamId=#{item.streamId}</if>" + | |
| 358 | - "<if test='item.hasAudio != null'>, hasAudio=#{item.hasAudio}</if>" + | |
| 302 | + "<if test='item.streamId != null'>, stream_id=#{item.streamId}</if>" + | |
| 303 | + "<if test='item.hasAudio != null'>, has_audio=#{item.hasAudio}</if>" + | |
| 359 | 304 | "<if test='item.longitude != null'>, longitude=#{item.longitude}</if>" + |
| 360 | 305 | "<if test='item.latitude != null'>, latitude=#{item.latitude}</if>" + |
| 361 | - "<if test='item.longitudeGcj02 != null'>, longitudeGcj02=#{item.longitudeGcj02}</if>" + | |
| 362 | - "<if test='item.latitudeGcj02 != null'>, latitudeGcj02=#{item.latitudeGcj02}</if>" + | |
| 363 | - "<if test='item.longitudeWgs84 != null'>, longitudeWgs84=#{item.longitudeWgs84}</if>" + | |
| 364 | - "<if test='item.latitudeWgs84 != null'>, latitudeWgs84=#{item.latitudeWgs84}</if>" + | |
| 365 | - "<if test='item.businessGroupId != null'>, businessGroupId=#{item.businessGroupId}</if>" + | |
| 366 | - "<if test='item.gpsTime != null'>, gpsTime=#{item.gpsTime}</if>" + | |
| 306 | + "<if test='item.longitudeGcj02 != null'>, longitude_gcj02=#{item.longitudeGcj02}</if>" + | |
| 307 | + "<if test='item.latitudeGcj02 != null'>, latitude_gcj02=#{item.latitudeGcj02}</if>" + | |
| 308 | + "<if test='item.longitudeWgs84 != null'>, longitude_wgs84=#{item.longitudeWgs84}</if>" + | |
| 309 | + "<if test='item.latitudeWgs84 != null'>, latitude_wgs84=#{item.latitudeWgs84}</if>" + | |
| 310 | + "<if test='item.businessGroupId != null'>, business_group_id=#{item.businessGroupId}</if>" + | |
| 311 | + "<if test='item.gpsTime != null'>, gps_time=#{item.gpsTime}</if>" + | |
| 367 | 312 | "<if test='item.id > 0'>WHERE id=#{item.id}</if>" + |
| 368 | - "<if test='item.id == 0'>WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}</if>" + | |
| 313 | + "<if test='item.id == 0'>WHERE device_id=#{item.deviceId} AND channel_id=#{item.channelId}</if>" + | |
| 369 | 314 | "</foreach>" + |
| 370 | 315 | "</script>"}) |
| 371 | 316 | int batchUpdate(List<DeviceChannel> updateChannels); |
| 372 | 317 | |
| 373 | 318 | |
| 374 | - @Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND status=1") | |
| 319 | + @Select("SELECT * FROM wvp_device_channel WHERE device_id=#{deviceId} AND status=true") | |
| 375 | 320 | List<DeviceChannel> queryOnlineChannelsByDeviceId(String deviceId); |
| 376 | 321 | |
| 377 | 322 | @Delete(value = {" <script>" + |
| 378 | 323 | "DELETE " + |
| 379 | 324 | "from " + |
| 380 | - "device_channel " + | |
| 325 | + "wvp_device_channel " + | |
| 381 | 326 | "WHERE " + |
| 382 | - "deviceId = #{deviceId} " + | |
| 383 | - " AND channelId NOT IN " + | |
| 327 | + "device_id = #{deviceId} " + | |
| 328 | + " AND channel_id NOT IN " + | |
| 384 | 329 | "<foreach collection='channels' item='item' open='(' separator=',' close=')' > #{item.channelId}</foreach>" + |
| 385 | 330 | " </script>"}) |
| 386 | 331 | int cleanChannelsNotInList(String deviceId, List<DeviceChannel> channels); |
| 387 | 332 | |
| 388 | - @Update(" update device_channel" + | |
| 389 | - " set subCount = (select *" + | |
| 333 | + @Update(" update wvp_device_channel" + | |
| 334 | + " set sub_count = (select *" + | |
| 390 | 335 | " from (select count(0)" + |
| 391 | - " from device_channel" + | |
| 392 | - " where deviceId = #{deviceId} and parentId = #{channelId}) as temp)" + | |
| 393 | - " where deviceId = #{deviceId} " + | |
| 394 | - " and channelId = #{channelId}") | |
| 336 | + " from wvp_device_channel" + | |
| 337 | + " where device_id = #{deviceId} and parent_id = #{channelId}) as temp)" + | |
| 338 | + " where device_id = #{deviceId} " + | |
| 339 | + " and channel_id = #{channelId}") | |
| 395 | 340 | int updateChannelSubCount(String deviceId, String channelId); |
| 396 | 341 | |
| 397 | 342 | @Update(value = {" <script>" + |
| 398 | - "UPDATE device_channel " + | |
| 343 | + "UPDATE wvp_device_channel " + | |
| 399 | 344 | "SET " + |
| 400 | 345 | "latitude=#{latitude}, " + |
| 401 | 346 | "longitude=#{longitude}, " + |
| 402 | - "longitudeGcj02=#{longitudeGcj02}, " + | |
| 403 | - "latitudeGcj02=#{latitudeGcj02}, " + | |
| 404 | - "longitudeWgs84=#{longitudeWgs84}, " + | |
| 405 | - "latitudeWgs84=#{latitudeWgs84}, " + | |
| 406 | - "gpsTime=#{gpsTime} " + | |
| 407 | - "WHERE deviceId=#{deviceId} " + | |
| 408 | - " <if test='channelId != null' > AND channelId=#{channelId}</if>" + | |
| 347 | + "longitude_gcj02=#{longitudeGcj02}, " + | |
| 348 | + "latitude_gcj02=#{latitudeGcj02}, " + | |
| 349 | + "longitude_wgs84=#{longitudeWgs84}, " + | |
| 350 | + "latitude_wgs84=#{latitudeWgs84}, " + | |
| 351 | + "gps_time=#{gpsTime} " + | |
| 352 | + "WHERE device_id=#{deviceId} " + | |
| 353 | + " <if test='channelId != null' > AND channel_id=#{channelId}</if>" + | |
| 409 | 354 | " </script>"}) |
| 410 | 355 | void updatePosition(DeviceChannel deviceChannel); |
| 411 | 356 | |
| 412 | - @Select("SELECT * FROM device_channel WHERE length(trim(streamId)) > 0") | |
| 357 | + @Select("SELECT * FROM wvp_device_channel WHERE length(trim(stream_id)) > 0") | |
| 413 | 358 | List<DeviceChannel> getAllChannelInPlay(); |
| 414 | 359 | |
| 415 | - @Select("select * from device_channel where longitude*latitude > 0 and deviceId = #{deviceId}") | |
| 360 | + @Select("select * from wvp_device_channel where longitude*latitude > 0 and device_id = #{deviceId}") | |
| 416 | 361 | List<DeviceChannel> getAllChannelWithCoordinate(String deviceId); |
| 417 | 362 | |
| 418 | 363 | |
| 419 | 364 | @Select(value = {" <script>" + |
| 420 | 365 | "select * " + |
| 421 | - "from device_channel " + | |
| 422 | - "where deviceId=#{deviceId}" + | |
| 423 | - " <if test='parentId != null and length != null' > and parentId = #{parentId} or left(channelId, LENGTH(#{parentId})) = #{parentId} and length(channelId)=#{length} </if>" + | |
| 424 | - " <if test='parentId == null and length != null' > and parentId = #{parentId} or length(channelId)=#{length} </if>" + | |
| 425 | - " <if test='parentId == null and length == null' > and parentId = #{parentId} </if>" + | |
| 426 | - " <if test='parentId != null and length == null' > and parentId = #{parentId} or left(channelId, LENGTH(#{parentId})) = #{parentId} </if>" + | |
| 366 | + "from wvp_device_channel " + | |
| 367 | + "where device_id=#{deviceId}" + | |
| 368 | + " <if test='parentId != null and length != null' > and parent_id= #{parentId} or left(channel_id, LENGTH(#{parentId})) = #{parentId} and length(channel_id)=#{length} </if>" + | |
| 369 | + " <if test='parentId == null and length != null' > and parent_id= #{parentId} or length(channel_id)=#{length} </if>" + | |
| 370 | + " <if test='parentId == null and length == null' > and parent_id= #{parentId} </if>" + | |
| 371 | + " <if test='parentId != null and length == null' > and parent_id= #{parentId} or left(channel_id, LENGTH(#{parentId})) = #{parentId} </if>" + | |
| 427 | 372 | " </script>"}) |
| 428 | 373 | List<DeviceChannel> getChannelsWithCivilCodeAndLength(String deviceId, String parentId, Integer length); |
| 429 | 374 | |
| 430 | 375 | @Select(value = {" <script>" + |
| 431 | 376 | "select * " + |
| 432 | - "from device_channel " + | |
| 433 | - "where deviceId=#{deviceId} and length(channelId)>14 and civilCode=#{parentId}" + | |
| 377 | + "from wvp_device_channel " + | |
| 378 | + "where device_id=#{deviceId} and length(channel_id)>14 and civil_code=#{parentId}" + | |
| 434 | 379 | " </script>"}) |
| 435 | 380 | List<DeviceChannel> getChannelsByCivilCode(String deviceId, String parentId); |
| 436 | 381 | |
| 437 | - @Select("select min(length(channelId)) as minLength " + | |
| 438 | - "from device_channel " + | |
| 439 | - "where deviceId=#{deviceId}") | |
| 382 | + @Select("select min(length(channel_id)) as minLength " + | |
| 383 | + "from wvp_device_channel " + | |
| 384 | + "where device_id=#{deviceId}") | |
| 440 | 385 | Integer getChannelMinLength(String deviceId); |
| 441 | 386 | |
| 442 | - @Select("select * from device_channel where deviceId=#{deviceId} and civilCode not in " + | |
| 443 | - "(select civilCode from device_channel where deviceId=#{deviceId} group by civilCode)") | |
| 444 | - List<DeviceChannel> getChannelWithoutCiviCode(String deviceId); | |
| 387 | + @Select("select * from wvp_device_channel where device_id=#{deviceId} and civil_code not in " + | |
| 388 | + "(select civil_code from wvp_device_channel where device_id=#{deviceId} group by civil_code)") | |
| 389 | + List<DeviceChannel> getChannelWithoutCivilCode(String deviceId); | |
| 445 | 390 | |
| 446 | - @Select("select * from device_channel where deviceId=#{deviceId} and SUBSTRING(channelId, 11, 3)=#{typeCode}") | |
| 391 | + @Select("select * from wvp_device_channel where device_id=#{deviceId} and SUBSTRING(channel_id, 11, 3)=#{typeCode}") | |
| 447 | 392 | List<DeviceChannel> getBusinessGroups(String deviceId, String typeCode); |
| 448 | 393 | |
| 449 | - @Select("select dc.id, dc.channelId, dc.deviceId, dc.name, dc.manufacture,dc.model,dc.owner, pc.civilCode,dc.block, " + | |
| 450 | - " dc.address, '0' as parental,'0' as channelType, pc.id as parentId, dc.safetyWay, dc.registerWay,dc.certNum, dc.certifiable, " + | |
| 451 | - " dc.errCode,dc.endTime, dc.secrecy, dc.ipAddress, dc.port, dc.PTZType, dc.password, dc.status, " + | |
| 452 | - " dc.longitudeWgs84 as longitude, dc.latitudeWgs84 as latitude, pc.businessGroupId " + | |
| 453 | - " from device_channel dc" + | |
| 454 | - " left join platform_gb_channel pgc on dc.id = pgc.deviceChannelId" + | |
| 455 | - " left join platform_catalog pc on pgc.catalogId = pc.id and pgc.platformId = pc.platformId" + | |
| 456 | - " where pgc.platformId=#{serverGBId}") | |
| 394 | + @Select("select dc.id, dc.channel_id, dc.device_id, dc.name, dc.manufacture,dc.model,dc.owner, pc.civil_code,dc.block, " + | |
| 395 | + " dc.address, '0' as parental,'0' as channel_type, pc.id as parent_id, dc.safety_way, dc.register_way,dc.cert_num, dc.certifiable, " + | |
| 396 | + " dc.err_code,dc.end_time, dc.secrecy, dc.ip_address, dc.port, dc.ptz_type, dc.password, dc.status, " + | |
| 397 | + " dc.longitude_wgs84 as longitude, dc.latitude_wgs84 as latitude, pc.business_group_id " + | |
| 398 | + " from wvp_device_channel dc" + | |
| 399 | + " LEFT JOIN wvp_platform_gb_channel pgc on dc.id = pgc.device_channel_id" + | |
| 400 | + " LEFT JOIN wvp_platform_catalog pc on pgc.catalog_id = pc.id and pgc.platform_id = pc.platform_id" + | |
| 401 | + " where pgc.platform_id=#{serverGBId}") | |
| 457 | 402 | List<DeviceChannel> queryChannelWithCatalog(String serverGBId); |
| 458 | 403 | |
| 459 | - @Select("select * from device_channel where deviceId = #{deviceId}") | |
| 404 | + @Select("select * from wvp_device_channel where device_id = #{deviceId}") | |
| 460 | 405 | List<DeviceChannel> queryAllChannels(String deviceId); |
| 461 | 406 | |
| 462 | 407 | |
| 463 | - @Select("select count(1) as total, sum(status) as online from device_channel") | |
| 464 | - ResourceBaceInfo getOverview(); | |
| 465 | - | |
| 466 | 408 | @Select("select channelId" + |
| 467 | - ", deviceId" + | |
| 409 | + ", device_id" + | |
| 468 | 410 | ", latitude" + |
| 469 | - ", longitude" + | |
| 470 | - ", latitudeWgs84" + | |
| 471 | - ", longitudeWgs84" + | |
| 472 | - ", latitudeGcj02" + | |
| 473 | - ", longitudeGcj02 " + | |
| 474 | - "from device_channel where deviceId = #{deviceId} " + | |
| 411 | + ", longitude"+ | |
| 412 | + ",latitude_wgs84"+ | |
| 413 | + ",longitude_wgs84"+ | |
| 414 | + ",latitude_gcj02"+ | |
| 415 | + ",longitude_gcj02"+ | |
| 416 | + "from wvp_device_channel where device_id = #{deviceId} " + | |
| 475 | 417 | "and latitude != 0 " + |
| 476 | 418 | "and longitude != 0 " + |
| 477 | - "and (latitudeGcj02 = 0 or latitudeWgs84 = 0 or longitudeWgs84 = 0 or longitudeGcj02 = 0)") | |
| 419 | + "and(latitude_gcj02=0 or latitude_wgs84=0 or longitude_wgs84= 0 or longitude_gcj02 = 0)") | |
| 478 | 420 | List<DeviceChannel> getChannelsWithoutTransform(String deviceId); |
| 479 | 421 | |
| 480 | - @Select("select de.* from device de left join device_channel dc on de.deviceId = dc.deviceId where dc.channelId=#{channelId}") | |
| 422 | + @Select("select de.* from wvp_device de left join wvp_device_channel dc on de.device_id = dc.deviceId where dc.channel_id=#{channelId}") | |
| 481 | 423 | List<Device> getDeviceByChannelId(String channelId); |
| 482 | 424 | |
| 483 | 425 | |
| 484 | 426 | @Delete({"<script>" + |
| 485 | 427 | "<foreach collection='deleteChannelList' item='item' separator=';'>" + |
| 486 | - "DELETE FROM device_channel WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}" + | |
| 428 | + "DELETE FROM wvp_device_channel WHERE device_id=#{item.deviceId} AND channel_id=#{item.channelId}" + | |
| 487 | 429 | "</foreach>" + |
| 488 | 430 | "</script>"}) |
| 489 | 431 | int batchDel(List<DeviceChannel> deleteChannelList); |
| 490 | 432 | |
| 491 | 433 | @Update({"<script>" + |
| 492 | 434 | "<foreach collection='channels' item='item' separator=';'>" + |
| 493 | - "UPDATE device_channel SET status=1 WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}" + | |
| 435 | + "UPDATE wvp_device_channel SET status=true WHERE device_id=#{item.deviceId} AND channel_id=#{item.channelId}" + | |
| 494 | 436 | "</foreach>" + |
| 495 | 437 | "</script>"}) |
| 496 | 438 | int batchOnline(List<DeviceChannel> channels); |
| 497 | 439 | |
| 498 | 440 | @Update({"<script>" + |
| 499 | 441 | "<foreach collection='channels' item='item' separator=';'>" + |
| 500 | - "UPDATE device_channel SET status=0 WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}" + | |
| 442 | + "UPDATE wvp_device_channel SET status= false WHERE device_id=#{item.deviceId} AND channel_id=#{item.channelId}" + | |
| 501 | 443 | "</foreach>" + |
| 502 | 444 | "</script>"}) |
| 503 | 445 | int batchOffline(List<DeviceChannel> channels); |
| 446 | + | |
| 447 | + | |
| 448 | + @Select("select count(1) from wvp_device_channel where status = true") | |
| 449 | + int getOnlineCount(); | |
| 450 | + | |
| 451 | + @Select("select count(1) from wvp_device_channel") | |
| 452 | + int getAllChannelCount(); | |
| 453 | + | |
| 454 | + // 设备主子码流逻辑START | |
| 455 | + @Update(value = {"UPDATE wvp_device_channel SET stream_id=null WHERE device_id=#{deviceId}"}) | |
| 456 | + void clearPlay(String deviceId); | |
| 457 | + // 设备主子码流逻辑END | |
| 458 | + @Select(value = {" <script>" + | |
| 459 | + "select * " + | |
| 460 | + "from wvp_device_channel " + | |
| 461 | + "where device_id=#{deviceId}" + | |
| 462 | + " <if test='parentId != null '> and parent_id = #{parentId} </if>" + | |
| 463 | + " <if test='parentId == null '> and parent_id is null </if>" + | |
| 464 | + " <if test='onlyCatalog == true '> and parental = 1 </if>" + | |
| 465 | + " </script>"}) | |
| 466 | + List<DeviceChannel> getSubChannelsByDeviceId(String deviceId, String parentId, boolean onlyCatalog); | |
| 467 | + | |
| 504 | 468 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
| 1 | 1 | package com.genersoft.iot.vmp.storager.dao; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 4 | -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; | |
| 5 | 4 | import org.apache.ibatis.annotations.*; |
| 6 | 5 | import org.springframework.stereotype.Repository; |
| 7 | 6 | |
| ... | ... | @@ -15,68 +14,67 @@ import java.util.List; |
| 15 | 14 | public interface DeviceMapper { |
| 16 | 15 | |
| 17 | 16 | @Select("SELECT " + |
| 18 | - "deviceId, " + | |
| 17 | + "device_id, " + | |
| 19 | 18 | "coalesce(custom_name, name) as name, " + |
| 20 | 19 | "password, " + |
| 21 | 20 | "manufacturer, " + |
| 22 | 21 | "model, " + |
| 23 | 22 | "firmware, " + |
| 24 | 23 | "transport," + |
| 25 | - "streamMode," + | |
| 24 | + "stream_mode," + | |
| 26 | 25 | "ip," + |
| 27 | - "sdpIp," + | |
| 28 | - "localIp," + | |
| 26 | + "sdp_ip," + | |
| 27 | + "local_ip," + | |
| 29 | 28 | "port," + |
| 30 | - "hostAddress," + | |
| 29 | + "host_address," + | |
| 31 | 30 | "expires," + |
| 32 | - "registerTime," + | |
| 33 | - "keepaliveTime," + | |
| 34 | - "createTime," + | |
| 35 | - "updateTime," + | |
| 31 | + "register_time," + | |
| 32 | + "keepalive_time," + | |
| 33 | + "create_time," + | |
| 34 | + "update_time," + | |
| 36 | 35 | "charset," + |
| 37 | - "subscribeCycleForCatalog," + | |
| 38 | - "subscribeCycleForMobilePosition," + | |
| 39 | - "mobilePositionSubmissionInterval," + | |
| 40 | - "subscribeCycleForAlarm," + | |
| 41 | - "ssrcCheck," + | |
| 42 | - "asMessageChannel," + | |
| 43 | - "geoCoordSys," + | |
| 44 | - "treeType," + | |
| 45 | - "online," + | |
| 46 | - "mediaServerId," + | |
| 47 | - "(SELECT count(0) FROM device_channel WHERE deviceId=device.deviceId) as channelCount "+ | |
| 48 | - " FROM device WHERE deviceId = #{deviceId}") | |
| 36 | + "subscribe_cycle_for_catalog," + | |
| 37 | + "subscribe_cycle_for_mobile_position," + | |
| 38 | + "mobile_position_submission_interval," + | |
| 39 | + "subscribe_cycle_for_alarm," + | |
| 40 | + "ssrc_check," + | |
| 41 | + "as_message_channel," + | |
| 42 | + "geo_coord_sys," + | |
| 43 | + "on_line," + | |
| 44 | + "media_server_id," + | |
| 45 | + "switch_primary_sub_stream," + | |
| 46 | + "(SELECT count(0) FROM wvp_device_channel WHERE device_id=wvp_device.device_id) as channel_count "+ | |
| 47 | + " FROM wvp_device WHERE device_id = #{deviceId}") | |
| 49 | 48 | Device getDeviceByDeviceId(String deviceId); |
| 50 | 49 | |
| 51 | - @Insert("INSERT INTO device (" + | |
| 52 | - "deviceId, " + | |
| 50 | + @Insert("INSERT INTO wvp_device (" + | |
| 51 | + "device_id, " + | |
| 53 | 52 | "name, " + |
| 54 | 53 | "manufacturer, " + |
| 55 | 54 | "model, " + |
| 56 | 55 | "firmware, " + |
| 57 | 56 | "transport," + |
| 58 | - "streamMode," + | |
| 57 | + "stream_mode," + | |
| 59 | 58 | "ip," + |
| 60 | - "sdpIp," + | |
| 61 | - "localIp," + | |
| 59 | + "sdp_ip," + | |
| 60 | + "local_ip," + | |
| 62 | 61 | "port," + |
| 63 | - "hostAddress," + | |
| 62 | + "host_address," + | |
| 64 | 63 | "expires," + |
| 65 | - "registerTime," + | |
| 66 | - "keepaliveTime," + | |
| 67 | - "keepaliveIntervalTime," + | |
| 68 | - "createTime," + | |
| 69 | - "updateTime," + | |
| 64 | + "register_time," + | |
| 65 | + "keepalive_time," + | |
| 66 | + "keepalive_interval_time," + | |
| 67 | + "create_time," + | |
| 68 | + "update_time," + | |
| 70 | 69 | "charset," + |
| 71 | - "subscribeCycleForCatalog," + | |
| 72 | - "subscribeCycleForMobilePosition," + | |
| 73 | - "mobilePositionSubmissionInterval," + | |
| 74 | - "subscribeCycleForAlarm," + | |
| 75 | - "ssrcCheck," + | |
| 76 | - "asMessageChannel," + | |
| 77 | - "geoCoordSys," + | |
| 78 | - "treeType," + | |
| 79 | - "online" + | |
| 70 | + "subscribe_cycle_for_catalog," + | |
| 71 | + "subscribe_cycle_for_mobile_position,"+ | |
| 72 | + "mobile_position_submission_interval,"+ | |
| 73 | + "subscribe_cycle_for_alarm,"+ | |
| 74 | + "ssrc_check,"+ | |
| 75 | + "as_message_channel,"+ | |
| 76 | + "geo_coord_sys,"+ | |
| 77 | + "on_line"+ | |
| 80 | 78 | ") VALUES (" + |
| 81 | 79 | "#{deviceId}," + |
| 82 | 80 | "#{name}," + |
| ... | ... | @@ -104,173 +102,172 @@ public interface DeviceMapper { |
| 104 | 102 | "#{ssrcCheck}," + |
| 105 | 103 | "#{asMessageChannel}," + |
| 106 | 104 | "#{geoCoordSys}," + |
| 107 | - "#{treeType}," + | |
| 108 | - "#{online}" + | |
| 105 | + "#{onLine}" + | |
| 109 | 106 | ")") |
| 110 | 107 | int add(Device device); |
| 111 | 108 | |
| 112 | 109 | @Update(value = {" <script>" + |
| 113 | - "UPDATE device " + | |
| 114 | - "SET updateTime=#{updateTime}" + | |
| 110 | + "UPDATE wvp_device " + | |
| 111 | + "SET update_time=#{updateTime}" + | |
| 115 | 112 | "<if test=\"name != null\">, name=#{name}</if>" + |
| 116 | 113 | "<if test=\"manufacturer != null\">, manufacturer=#{manufacturer}</if>" + |
| 117 | 114 | "<if test=\"model != null\">, model=#{model}</if>" + |
| 118 | 115 | "<if test=\"firmware != null\">, firmware=#{firmware}</if>" + |
| 119 | 116 | "<if test=\"transport != null\">, transport=#{transport}</if>" + |
| 120 | 117 | "<if test=\"ip != null\">, ip=#{ip}</if>" + |
| 121 | - "<if test=\"localIp != null\">, localIp=#{localIp}</if>" + | |
| 118 | + "<if test=\"localIp != null\">, local_ip=#{localIp}</if>" + | |
| 122 | 119 | "<if test=\"port != null\">, port=#{port}</if>" + |
| 123 | - "<if test=\"hostAddress != null\">, hostAddress=#{hostAddress}</if>" + | |
| 124 | - "<if test=\"online != null\">, online=#{online}</if>" + | |
| 125 | - "<if test=\"registerTime != null\">, registerTime=#{registerTime}</if>" + | |
| 126 | - "<if test=\"keepaliveTime != null\">, keepaliveTime=#{keepaliveTime}</if>" + | |
| 127 | - "<if test=\"keepaliveIntervalTime != null\">, keepaliveIntervalTime=#{keepaliveIntervalTime}</if>" + | |
| 120 | + "<if test=\"hostAddress != null\">, host_address=#{hostAddress}</if>" + | |
| 121 | + "<if test=\"onLine != null\">, on_line=#{onLine}</if>" + | |
| 122 | + "<if test=\"registerTime != null\">, register_time=#{registerTime}</if>" + | |
| 123 | + "<if test=\"keepaliveTime != null\">, keepalive_time=#{keepaliveTime}</if>" + | |
| 124 | + "<if test=\"keepaliveIntervalTime != null\">, keepalive_interval_time=#{keepaliveIntervalTime}</if>" + | |
| 128 | 125 | "<if test=\"expires != null\">, expires=#{expires}</if>" + |
| 129 | - "WHERE deviceId=#{deviceId}"+ | |
| 126 | + "WHERE device_id=#{deviceId}"+ | |
| 130 | 127 | " </script>"}) |
| 131 | 128 | int update(Device device); |
| 132 | 129 | |
| 133 | 130 | @Select( |
| 134 | 131 | " <script>" + |
| 135 | 132 | "SELECT " + |
| 136 | - "deviceId, " + | |
| 133 | + "device_id, " + | |
| 137 | 134 | "coalesce(custom_name, name) as name, " + |
| 138 | 135 | "password, " + |
| 139 | 136 | "manufacturer, " + |
| 140 | 137 | "model, " + |
| 141 | 138 | "firmware, " + |
| 142 | 139 | "transport," + |
| 143 | - "streamMode," + | |
| 144 | - "ip," + | |
| 145 | - "sdpIp," + | |
| 146 | - "localIp," + | |
| 147 | - "port," + | |
| 148 | - "hostAddress," + | |
| 149 | - "expires," + | |
| 150 | - "registerTime," + | |
| 151 | - "keepaliveTime," + | |
| 152 | - "createTime," + | |
| 153 | - "updateTime," + | |
| 154 | - "charset," + | |
| 155 | - "subscribeCycleForCatalog," + | |
| 156 | - "subscribeCycleForMobilePosition," + | |
| 157 | - "mobilePositionSubmissionInterval," + | |
| 158 | - "subscribeCycleForAlarm," + | |
| 159 | - "ssrcCheck," + | |
| 160 | - "asMessageChannel," + | |
| 161 | - "geoCoordSys," + | |
| 162 | - "treeType," + | |
| 163 | - "online," + | |
| 164 | - "mediaServerId," + | |
| 165 | - "(SELECT count(0) FROM device_channel WHERE deviceId=de.deviceId) as channelCount FROM device de" + | |
| 166 | - "<if test=\"online != null\"> where online=${online}</if>"+ | |
| 140 | + "stream_mode," + | |
| 141 | + "ip,"+ | |
| 142 | + "sdp_ip,"+ | |
| 143 | + "local_ip,"+ | |
| 144 | + "port,"+ | |
| 145 | + "host_address,"+ | |
| 146 | + "expires,"+ | |
| 147 | + "register_time,"+ | |
| 148 | + "keepalive_time,"+ | |
| 149 | + "create_time,"+ | |
| 150 | + "update_time,"+ | |
| 151 | + "charset,"+ | |
| 152 | + "subscribe_cycle_for_catalog,"+ | |
| 153 | + "subscribe_cycle_for_mobile_position,"+ | |
| 154 | + "mobile_position_submission_interval,"+ | |
| 155 | + "subscribe_cycle_for_alarm,"+ | |
| 156 | + "ssrc_check,"+ | |
| 157 | + "as_message_channel,"+ | |
| 158 | + "geo_coord_sys,"+ | |
| 159 | + "on_line,"+ | |
| 160 | + "media_server_id,"+ | |
| 161 | + "switch_primary_sub_stream switchPrimarySubStream,"+ | |
| 162 | + "(SELECT count(0) FROM wvp_device_channel WHERE device_id=de.device_id) as channel_count " + | |
| 163 | + "FROM wvp_device de" + | |
| 164 | + "<if test=\"onLine != null\"> where on_line=${onLine}</if>"+ | |
| 165 | + " order by create_time desc "+ | |
| 167 | 166 | " </script>" |
| 168 | 167 | ) |
| 169 | - List<Device> getDevices(Boolean online); | |
| 168 | + List<Device> getDevices(Boolean onLine); | |
| 170 | 169 | |
| 171 | - @Delete("DELETE FROM device WHERE deviceId=#{deviceId}") | |
| 170 | + @Delete("DELETE FROM wvp_device WHERE device_id=#{deviceId}") | |
| 172 | 171 | int del(String deviceId); |
| 173 | 172 | |
| 174 | 173 | @Select("SELECT " + |
| 175 | - "deviceId, " + | |
| 174 | + "device_id, " + | |
| 176 | 175 | "coalesce(custom_name, name) as name, " + |
| 177 | 176 | "password, " + |
| 178 | 177 | "manufacturer, " + |
| 179 | 178 | "model, " + |
| 180 | 179 | "firmware, " + |
| 181 | 180 | "transport," + |
| 182 | - "streamMode," + | |
| 181 | + "stream_mode," + | |
| 183 | 182 | "ip," + |
| 184 | - "sdpIp," + | |
| 185 | - "localIp," + | |
| 186 | - "port," + | |
| 187 | - "hostAddress," + | |
| 188 | - "expires," + | |
| 189 | - "registerTime," + | |
| 190 | - "keepaliveTime," + | |
| 191 | - "createTime," + | |
| 192 | - "updateTime," + | |
| 193 | - "charset," + | |
| 194 | - "subscribeCycleForCatalog," + | |
| 195 | - "subscribeCycleForMobilePosition," + | |
| 196 | - "mobilePositionSubmissionInterval," + | |
| 197 | - "subscribeCycleForAlarm," + | |
| 198 | - "ssrcCheck," + | |
| 199 | - "asMessageChannel," + | |
| 200 | - "geoCoordSys," + | |
| 201 | - "treeType," + | |
| 202 | - "online " + | |
| 203 | - " FROM device WHERE online = 1") | |
| 183 | + "sdp_ip,"+ | |
| 184 | + "local_ip,"+ | |
| 185 | + "port,"+ | |
| 186 | + "host_address,"+ | |
| 187 | + "expires,"+ | |
| 188 | + "register_time,"+ | |
| 189 | + "keepalive_time,"+ | |
| 190 | + "create_time,"+ | |
| 191 | + "update_time,"+ | |
| 192 | + "charset,"+ | |
| 193 | + "subscribe_cycle_for_catalog,"+ | |
| 194 | + "subscribe_cycle_for_mobile_position,"+ | |
| 195 | + "mobile_position_submission_interval,"+ | |
| 196 | + "subscribe_cycle_for_alarm,"+ | |
| 197 | + "ssrc_check,"+ | |
| 198 | + "as_message_channel,"+ | |
| 199 | + "geo_coord_sys,"+ | |
| 200 | + "on_line"+ | |
| 201 | + " FROM wvp_device WHERE on_line = true") | |
| 204 | 202 | List<Device> getOnlineDevices(); |
| 205 | 203 | @Select("SELECT " + |
| 206 | - "deviceId, " + | |
| 207 | - "coalesce(custom_name, name) as name, " + | |
| 208 | - "password, " + | |
| 209 | - "manufacturer, " + | |
| 210 | - "model, " + | |
| 211 | - "firmware, " + | |
| 212 | - "transport," + | |
| 213 | - "streamMode," + | |
| 214 | - "ip," + | |
| 215 | - "sdpIp," + | |
| 216 | - "localIp," + | |
| 217 | - "port," + | |
| 218 | - "hostAddress," + | |
| 219 | - "expires," + | |
| 220 | - "registerTime," + | |
| 221 | - "keepaliveTime," + | |
| 222 | - "createTime," + | |
| 223 | - "updateTime," + | |
| 224 | - "charset," + | |
| 225 | - "subscribeCycleForCatalog," + | |
| 226 | - "subscribeCycleForMobilePosition," + | |
| 227 | - "mobilePositionSubmissionInterval," + | |
| 228 | - "subscribeCycleForAlarm," + | |
| 229 | - "ssrcCheck," + | |
| 230 | - "asMessageChannel," + | |
| 231 | - "geoCoordSys," + | |
| 232 | - "treeType," + | |
| 233 | - "online" + | |
| 234 | - " FROM device WHERE ip = #{host} AND port=#{port}") | |
| 204 | + "device_id,"+ | |
| 205 | + "coalesce(custom_name,name)as name,"+ | |
| 206 | + "password,"+ | |
| 207 | + "manufacturer,"+ | |
| 208 | + "model,"+ | |
| 209 | + "firmware,"+ | |
| 210 | + "transport,"+ | |
| 211 | + "stream_mode,"+ | |
| 212 | + "ip,"+ | |
| 213 | + "sdp_ip,"+ | |
| 214 | + "local_ip,"+ | |
| 215 | + "port,"+ | |
| 216 | + "host_address,"+ | |
| 217 | + "expires,"+ | |
| 218 | + "register_time,"+ | |
| 219 | + "keepalive_time,"+ | |
| 220 | + "create_time,"+ | |
| 221 | + "update_time,"+ | |
| 222 | + "charset,"+ | |
| 223 | + "subscribe_cycle_for_catalog,"+ | |
| 224 | + "subscribe_cycle_for_mobile_position,"+ | |
| 225 | + "mobile_position_submission_interval,"+ | |
| 226 | + "subscribe_cycle_for_alarm,"+ | |
| 227 | + "ssrc_check,"+ | |
| 228 | + "as_message_channel,"+ | |
| 229 | + "geo_coord_sys,"+ | |
| 230 | + "on_line"+ | |
| 231 | + " FROM wvp_device WHERE ip = #{host} AND port=#{port}") | |
| 235 | 232 | Device getDeviceByHostAndPort(String host, int port); |
| 236 | 233 | |
| 237 | 234 | @Update(value = {" <script>" + |
| 238 | - "UPDATE device " + | |
| 239 | - "SET updateTime=#{updateTime}" + | |
| 235 | + "UPDATE wvp_device " + | |
| 236 | + "SET update_time=#{updateTime}" + | |
| 240 | 237 | "<if test=\"name != null\">, custom_name=#{name}</if>" + |
| 241 | 238 | "<if test=\"password != null\">, password=#{password}</if>" + |
| 242 | - "<if test=\"streamMode != null\">, streamMode=#{streamMode}</if>" + | |
| 239 | + "<if test=\"streamMode != null\">, stream_mode=#{streamMode}</if>" + | |
| 243 | 240 | "<if test=\"ip != null\">, ip=#{ip}</if>" + |
| 244 | - "<if test=\"sdpIp != null\">, sdpIp=#{sdpIp}</if>" + | |
| 241 | + "<if test=\"sdpIp != null\">, sdp_ip=#{sdpIp}</if>" + | |
| 245 | 242 | "<if test=\"port != null\">, port=#{port}</if>" + |
| 246 | 243 | "<if test=\"charset != null\">, charset=#{charset}</if>" + |
| 247 | - "<if test=\"subscribeCycleForCatalog != null\">, subscribeCycleForCatalog=#{subscribeCycleForCatalog}</if>" + | |
| 248 | - "<if test=\"subscribeCycleForMobilePosition != null\">, subscribeCycleForMobilePosition=#{subscribeCycleForMobilePosition}</if>" + | |
| 249 | - "<if test=\"mobilePositionSubmissionInterval != null\">, mobilePositionSubmissionInterval=#{mobilePositionSubmissionInterval}</if>" + | |
| 250 | - "<if test=\"subscribeCycleForAlarm != null\">, subscribeCycleForAlarm=#{subscribeCycleForAlarm}</if>" + | |
| 251 | - "<if test=\"ssrcCheck != null\">, ssrcCheck=#{ssrcCheck}</if>" + | |
| 252 | - "<if test=\"asMessageChannel != null\">, asMessageChannel=#{asMessageChannel}</if>" + | |
| 253 | - "<if test=\"geoCoordSys != null\">, geoCoordSys=#{geoCoordSys}</if>" + | |
| 254 | - "<if test=\"treeType != null\">, treeType=#{treeType}</if>" + | |
| 255 | - "<if test=\"mediaServerId != null\">, mediaServerId=#{mediaServerId}</if>" + | |
| 256 | - "WHERE deviceId=#{deviceId}"+ | |
| 244 | + "<if test=\"subscribeCycleForCatalog != null\">, subscribe_cycle_for_catalog=#{subscribeCycleForCatalog}</if>" + | |
| 245 | + "<if test=\"subscribeCycleForMobilePosition != null\">, subscribe_cycle_for_mobile_position=#{subscribeCycleForMobilePosition}</if>" + | |
| 246 | + "<if test=\"mobilePositionSubmissionInterval != null\">, mobile_position_submission_interval=#{mobilePositionSubmissionInterval}</if>" + | |
| 247 | + "<if test=\"subscribeCycleForAlarm != null\">, subscribe_cycle_for_alarm=#{subscribeCycleForAlarm}</if>" + | |
| 248 | + "<if test=\"ssrcCheck != null\">, ssrc_check=#{ssrcCheck}</if>" + | |
| 249 | + "<if test=\"asMessageChannel != null\">, as_message_channel=#{asMessageChannel}</if>" + | |
| 250 | + "<if test=\"geoCoordSys != null\">, geo_coord_sys=#{geoCoordSys}</if>" + | |
| 251 | + "<if test=\"switchPrimarySubStream != null\">, switch_primary_sub_stream=#{switchPrimarySubStream}</if>" + | |
| 252 | + "<if test=\"mediaServerId != null\">, media_server_id=#{mediaServerId}</if>" + | |
| 253 | + "WHERE device_id=#{deviceId}"+ | |
| 257 | 254 | " </script>"}) |
| 258 | 255 | void updateCustom(Device device); |
| 259 | 256 | |
| 260 | - @Insert("INSERT INTO device (" + | |
| 261 | - "deviceId, " + | |
| 262 | - "custom_name, " + | |
| 263 | - "password, " + | |
| 264 | - "sdpIp, " + | |
| 265 | - "createTime," + | |
| 266 | - "updateTime," + | |
| 267 | - "charset," + | |
| 268 | - "ssrcCheck," + | |
| 269 | - "asMessageChannel," + | |
| 270 | - "geoCoordSys," + | |
| 271 | - "treeType," + | |
| 272 | - "online," + | |
| 273 | - "mediaServerId" + | |
| 257 | + @Insert("INSERT INTO wvp_device (" + | |
| 258 | + "device_id,"+ | |
| 259 | + "custom_name,"+ | |
| 260 | + "password,"+ | |
| 261 | + "sdp_ip,"+ | |
| 262 | + "create_time,"+ | |
| 263 | + "update_time,"+ | |
| 264 | + "charset,"+ | |
| 265 | + "ssrc_check,"+ | |
| 266 | + "as_message_channel,"+ | |
| 267 | + "geo_coord_sys,"+ | |
| 268 | + "on_line,"+ | |
| 269 | + "media_server_id,"+ | |
| 270 | + "switch_primary_sub_stream"+ | |
| 274 | 271 | ") VALUES (" + |
| 275 | 272 | "#{deviceId}," + |
| 276 | 273 | "#{name}," + |
| ... | ... | @@ -282,18 +279,15 @@ public interface DeviceMapper { |
| 282 | 279 | "#{ssrcCheck}," + |
| 283 | 280 | "#{asMessageChannel}," + |
| 284 | 281 | "#{geoCoordSys}," + |
| 285 | - "#{treeType}," + | |
| 286 | - "#{online}," + | |
| 287 | - "#{mediaServerId}" + | |
| 282 | + "#{onLine}," + | |
| 283 | + "#{mediaServerId}," + | |
| 284 | + "#{switchPrimarySubStream}" + | |
| 288 | 285 | ")") |
| 289 | 286 | void addCustomDevice(Device device); |
| 290 | 287 | |
| 291 | - @Select("select count(1) as total, sum(online) as online from device") | |
| 292 | - ResourceBaceInfo getOverview(); | |
| 293 | - | |
| 294 | - @Select("select * from device") | |
| 288 | + @Select("select * FROM wvp_device") | |
| 295 | 289 | List<Device> getAll(); |
| 296 | 290 | |
| 297 | - @Select("select * from device where asMessageChannel = 1") | |
| 291 | + @Select("select * FROM wvp_device where as_message_channel = true") | |
| 298 | 292 | List<Device> queryDeviceWithAsMessageChannel(); |
| 299 | 293 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java
| ... | ... | @@ -11,25 +11,25 @@ import java.util.List; |
| 11 | 11 | @Mapper |
| 12 | 12 | public interface DeviceMobilePositionMapper { |
| 13 | 13 | |
| 14 | - @Insert("INSERT INTO device_mobile_position (deviceId,channelId, deviceName, time, longitude, latitude, altitude, speed, direction, reportSource, longitudeGcj02, latitudeGcj02, longitudeWgs84, latitudeWgs84, createTime) " + | |
| 14 | + @Insert("INSERT INTO wvp_device_mobile_position (device_id,channel_id, device_name,time,longitude,latitude,altitude,speed,direction,report_source,longitude_gcj02,latitude_gcj02,longitude_wgs84,latitude_wgs84,create_time)"+ | |
| 15 | 15 | "VALUES (#{deviceId}, #{channelId}, #{deviceName}, #{time}, #{longitude}, #{latitude}, #{altitude}, #{speed}, #{direction}, #{reportSource}, #{longitudeGcj02}, #{latitudeGcj02}, #{longitudeWgs84}, #{latitudeWgs84}, #{createTime})") |
| 16 | 16 | int insertNewPosition(MobilePosition mobilePosition); |
| 17 | 17 | |
| 18 | 18 | @Select(value = {" <script>" + |
| 19 | - "SELECT * FROM device_mobile_position" + | |
| 20 | - " WHERE deviceId = #{deviceId}" + | |
| 21 | - "<if test=\"channelId != null\"> and channelId = #{channelId}</if>" + | |
| 19 | + "SELECT * FROM wvp_device_mobile_position" + | |
| 20 | + " WHERE device_id = #{deviceId}" + | |
| 21 | + "<if test=\"channelId != null\"> and channel_id = #{channelId}</if>" + | |
| 22 | 22 | "<if test=\"startTime != null\"> AND time>=#{startTime}</if>" + |
| 23 | 23 | "<if test=\"endTime != null\"> AND time<=#{endTime}</if>" + |
| 24 | 24 | " ORDER BY time ASC" + |
| 25 | 25 | " </script>"}) |
| 26 | 26 | List<MobilePosition> queryPositionByDeviceIdAndTime(String deviceId, String channelId, String startTime, String endTime); |
| 27 | 27 | |
| 28 | - @Select("SELECT * FROM device_mobile_position WHERE deviceId = #{deviceId}" + | |
| 28 | + @Select("SELECT * FROM wvp_device_mobile_position WHERE device_id = #{deviceId}" + | |
| 29 | 29 | " ORDER BY time DESC LIMIT 1") |
| 30 | 30 | MobilePosition queryLatestPositionByDevice(String deviceId); |
| 31 | 31 | |
| 32 | - @Delete("DELETE FROM device_mobile_position WHERE deviceId = #{deviceId}") | |
| 32 | + @Delete("DELETE FROM wvp_device_mobile_position WHERE device_id = #{deviceId}") | |
| 33 | 33 | int clearMobilePositionsByDeviceId(String deviceId); |
| 34 | 34 | |
| 35 | 35 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
| ... | ... | @@ -14,94 +14,94 @@ import java.util.List; |
| 14 | 14 | @Repository |
| 15 | 15 | public interface GbStreamMapper { |
| 16 | 16 | |
| 17 | - @Insert("REPLACE INTO gb_stream (app, stream, gbId, name, " + | |
| 18 | - "longitude, latitude, streamType, mediaServerId, createTime) VALUES" + | |
| 17 | + @Insert("REPLACE INTO wvp_gb_stream (app, stream, gb_id, name, " + | |
| 18 | + "longitude, latitude, stream_type,media_server_id,create_time) VALUES" + | |
| 19 | 19 | "(#{app}, #{stream}, #{gbId}, #{name}, " + |
| 20 | 20 | "#{longitude}, #{latitude}, #{streamType}, " + |
| 21 | 21 | "#{mediaServerId}, #{createTime})") |
| 22 | 22 | @Options(useGeneratedKeys = true, keyProperty = "gbStreamId", keyColumn = "gbStreamId") |
| 23 | 23 | int add(GbStream gbStream); |
| 24 | 24 | |
| 25 | - @Update("UPDATE gb_stream " + | |
| 25 | + @Update("UPDATE wvp_gb_stream " + | |
| 26 | 26 | "SET app=#{app}," + |
| 27 | 27 | "stream=#{stream}," + |
| 28 | - "gbId=#{gbId}," + | |
| 28 | + "gb_id=#{gbId}," + | |
| 29 | 29 | "name=#{name}," + |
| 30 | - "streamType=#{streamType}," + | |
| 30 | + "stream_type=#{streamType}," + | |
| 31 | 31 | "longitude=#{longitude}, " + |
| 32 | 32 | "latitude=#{latitude}," + |
| 33 | - "mediaServerId=#{mediaServerId}" + | |
| 33 | + "media_server_id=#{mediaServerId}" + | |
| 34 | 34 | "WHERE app=#{app} AND stream=#{stream}") |
| 35 | 35 | int updateByAppAndStream(GbStream gbStream); |
| 36 | 36 | |
| 37 | - @Update("UPDATE gb_stream " + | |
| 37 | + @Update("UPDATE wvp_gb_stream " + | |
| 38 | 38 | "SET app=#{app}," + |
| 39 | 39 | "stream=#{stream}," + |
| 40 | - "gbId=#{gbId}," + | |
| 40 | + "gb_id=#{gbId}," + | |
| 41 | 41 | "name=#{name}," + |
| 42 | - "streamType=#{streamType}," + | |
| 42 | + "stream_type=#{streamType}," + | |
| 43 | 43 | "longitude=#{longitude}, " + |
| 44 | 44 | "latitude=#{latitude}," + |
| 45 | - "mediaServerId=#{mediaServerId}" + | |
| 46 | - "WHERE gbStreamId=#{gbStreamId}") | |
| 45 | + "media_server_id=#{mediaServerId}" + | |
| 46 | + "WHERE gb_stream_id=#{gbStreamId}") | |
| 47 | 47 | int update(GbStream gbStream); |
| 48 | 48 | |
| 49 | - @Delete("DELETE FROM gb_stream WHERE app=#{app} AND stream=#{stream}") | |
| 49 | + @Delete("DELETE FROM wvp_gb_stream WHERE app=#{app} AND stream=#{stream}") | |
| 50 | 50 | int del(String app, String stream); |
| 51 | 51 | |
| 52 | 52 | @Select("<script> "+ |
| 53 | - "SELECT gs.* FROM gb_stream gs " + | |
| 53 | + "SELECT gs.* FROM wvp_gb_stream gs " + | |
| 54 | 54 | "WHERE " + |
| 55 | 55 | "1=1 " + |
| 56 | - " <if test='catalogId != null'> AND gs.gbStreamId in" + | |
| 57 | - "(select pgs.gbStreamId from platform_gb_stream pgs where pgs.platformId = #{platformId} and pgs.catalogId=#{catalogId})</if> " + | |
| 58 | - " <if test='catalogId == null'> AND gs.gbStreamId not in" + | |
| 59 | - "(select pgs.gbStreamId from platform_gb_stream pgs where pgs.platformId = #{platformId}) </if> " + | |
| 60 | - " <if test='query != null'> AND (gs.app LIKE concat('%',#{query},'%') OR gs.stream LIKE concat('%',#{query},'%') OR gs.gbId LIKE concat('%',#{query},'%') OR gs.name LIKE concat('%',#{query},'%'))</if> " + | |
| 61 | - " <if test='mediaServerId != null' > AND gs.mediaServerId=#{mediaServerId} </if>" + | |
| 62 | - " order by gs.gbStreamId asc " + | |
| 56 | + " <if test='catalogId != null'> AND gs.gb_stream_id in" + | |
| 57 | + "(select pgs.gb_stream_id from wvp_platform_gb_stream pgs where pgs.platform_id = #{platformId} and pgs.catalog_id=#{catalogId})</if> " + | |
| 58 | + " <if test='catalogId == null'> AND gs.gb_stream_id not in" + | |
| 59 | + "(select pgs.gb_stream_id from wvp_platform_gb_stream pgs where pgs.platform_id = #{platformId}) </if> " + | |
| 60 | + " <if test='query != null'> AND (gs.app LIKE concat('%',#{query},'%') OR gs.stream LIKE concat('%',#{query},'%') OR gs.gb_id LIKE concat('%',#{query},'%') OR gs.name LIKE concat('%',#{query},'%'))</if> " + | |
| 61 | + " <if test='mediaServerId != null' > AND gs.media_server_id=#{mediaServerId} </if>" + | |
| 62 | + " order by gs.gb_stream_id asc " + | |
| 63 | 63 | "</script>") |
| 64 | 64 | List<GbStream> selectAll(String platformId, String catalogId, String query, String mediaServerId); |
| 65 | 65 | |
| 66 | - @Select("SELECT * FROM gb_stream WHERE app=#{app} AND stream=#{stream}") | |
| 66 | + @Select("SELECT * FROM wvp_gb_stream WHERE app=#{app} AND stream=#{stream}") | |
| 67 | 67 | GbStream selectOne(String app, String stream); |
| 68 | 68 | |
| 69 | - @Select("SELECT * FROM gb_stream WHERE gbId=#{gbId}") | |
| 69 | + @Select("SELECT * FROM wvp_gb_stream WHERE gb_id=#{gbId}") | |
| 70 | 70 | List<GbStream> selectByGBId(String gbId); |
| 71 | 71 | |
| 72 | - @Select("SELECT gs.*, pgs.platformId as platformId, pgs.catalogId as catalogId FROM gb_stream gs " + | |
| 73 | - "LEFT JOIN platform_gb_stream pgs ON gs.gbStreamId = pgs.gbStreamId " + | |
| 74 | - "WHERE gs.gbId = #{gbId} AND pgs.platformId = #{platformId}") | |
| 72 | + @Select("SELECT gs.*, pgs.platform_id as platform_id, pgs.catalog_id as catalog_id FROM wvp_gb_stream gs " + | |
| 73 | + "LEFT JOIN wvp_platform_gb_stream pgs ON gs.gb_stream_id = pgs.gb_stream_id " + | |
| 74 | + "WHERE gs.gb_id = #{gbId} AND pgs.platform_id = #{platformId}") | |
| 75 | 75 | GbStream queryStreamInPlatform(String platformId, String gbId); |
| 76 | 76 | |
| 77 | 77 | @Select("<script> "+ |
| 78 | - "select gt.gbId as channelId, gt.name, 'wvp-pro' as manufacture, st.status, gt.longitude, gt.latitude, pc.id as parentId," + | |
| 79 | - " '1' as registerWay, pc.civilCode, 'live' as model, 'wvp-pro' as owner, '0' as parental,'0' as secrecy" + | |
| 80 | - " from gb_stream gt " + | |
| 78 | + "select gt.gb_id as channel_id, gt.name, 'wvp-pro' as manufacture, st.status, gt.longitude, gt.latitude, pc.id as parent_id," + | |
| 79 | + " '1' as register_way, pc.civil_code, 'live' as model, 'wvp-pro' as owner, '0' as parental,'0' as secrecy" + | |
| 80 | + " from wvp_gb_stream gt " + | |
| 81 | 81 | " left join (" + |
| 82 | 82 | " select " + |
| 83 | 83 | " <if test='usPushingAsStatus != true'> sp.status as status, </if>" + |
| 84 | - " <if test='usPushingAsStatus == true'> sp.pushIng as status, </if>" + | |
| 85 | - "sp.app, sp.stream from stream_push sp" + | |
| 84 | + " <if test='usPushingAsStatus == true'> sp.push_ing as status, </if>" + | |
| 85 | + "sp.app, sp.stream from wvp_stream_push sp" + | |
| 86 | 86 | " union all" + |
| 87 | - " select spxy.status, spxy.app, spxy.stream from stream_proxy spxy" + | |
| 87 | + " select spxy.status, spxy.app, spxy.stream from wvp_stream_proxy spxy" + | |
| 88 | 88 | " ) st on st.app = gt.app and st.stream = gt.stream" + |
| 89 | - " left join platform_gb_stream pgs on gt.gbStreamId = pgs.gbStreamId" + | |
| 90 | - " left join platform_catalog pc on pgs.catalogId = pc.id and pgs.platformId = pc.platformId" + | |
| 91 | - " where pgs.platformId=#{platformId}" + | |
| 89 | + " left join wvp_platform_gb_stream pgs on gt.gb_stream_id = pgs.gb_stream_id" + | |
| 90 | + " left join wvp_platform_catalog pc on pgs.catalog_id = pc.id and pgs.platform_id = pc.platform_id" + | |
| 91 | + " where pgs.platform_id=#{platformId}" + | |
| 92 | 92 | "</script>") |
| 93 | 93 | List<DeviceChannel> queryGbStreamListInPlatform(String platformId, boolean usPushingAsStatus); |
| 94 | 94 | |
| 95 | 95 | |
| 96 | - @Select("SELECT gs.* FROM gb_stream gs LEFT JOIN platform_gb_stream pgs " + | |
| 97 | - "ON gs.gbStreamId = pgs.gbStreamId WHERE pgs.gbStreamId is NULL") | |
| 96 | + @Select("SELECT gs.* FROM wvp_gb_stream gs left join wvp_platform_gb_stream pgs " + | |
| 97 | + "ON gs.gb_stream_id = pgs.gb_stream_id WHERE pgs.gb_stream_id is NULL") | |
| 98 | 98 | List<GbStream> queryStreamNotInPlatform(); |
| 99 | 99 | |
| 100 | - @Delete("DELETE FROM gb_stream WHERE streamType=#{type} AND gbId=NULL AND mediaServerId=#{mediaServerId}") | |
| 100 | + @Delete("DELETE FROM wvp_gb_stream WHERE stream_type=#{type} AND gb_id=NULL AND media_server_id=#{mediaServerId}") | |
| 101 | 101 | void deleteWithoutGBId(String type, String mediaServerId); |
| 102 | 102 | |
| 103 | 103 | @Delete("<script> "+ |
| 104 | - "DELETE FROM gb_stream where " + | |
| 104 | + "DELETE FROM wvp_gb_stream where " + | |
| 105 | 105 | "<foreach collection='streamProxyItemList' item='item' separator='or'>" + |
| 106 | 106 | "(app=#{item.app} and stream=#{item.stream}) " + |
| 107 | 107 | "</foreach>" + |
| ... | ... | @@ -109,7 +109,7 @@ public interface GbStreamMapper { |
| 109 | 109 | void batchDel(List<StreamProxyItem> streamProxyItemList); |
| 110 | 110 | |
| 111 | 111 | @Delete("<script> "+ |
| 112 | - "DELETE FROM gb_stream where " + | |
| 112 | + "DELETE FROM wvp_gb_stream where " + | |
| 113 | 113 | "<foreach collection='gbStreams' item='item' separator='or'>" + |
| 114 | 114 | "(app=#{item.app} and stream=#{item.stream}) " + |
| 115 | 115 | "</foreach>" + |
| ... | ... | @@ -117,9 +117,9 @@ public interface GbStreamMapper { |
| 117 | 117 | void batchDelForGbStream(List<GbStream> gbStreams); |
| 118 | 118 | |
| 119 | 119 | @Insert("<script> " + |
| 120 | - "INSERT IGNORE into gb_stream " + | |
| 121 | - "(app, stream, gbId, name, " + | |
| 122 | - "longitude, latitude, streamType, mediaServerId, createTime)" + | |
| 120 | + "INSERT into wvp_gb_stream " + | |
| 121 | + "(app, stream, gb_id, name, " + | |
| 122 | + "longitude, latitude, stream_type,media_server_id,create_time)" + | |
| 123 | 123 | "values " + |
| 124 | 124 | "<foreach collection='subList' index='index' item='item' separator=','> " + |
| 125 | 125 | "(#{item.app}, #{item.stream}, #{item.gbId}, #{item.name}, " + |
| ... | ... | @@ -127,46 +127,46 @@ public interface GbStreamMapper { |
| 127 | 127 | "#{item.mediaServerId}, #{item.createTime}) "+ |
| 128 | 128 | "</foreach> " + |
| 129 | 129 | "</script>") |
| 130 | - @Options(useGeneratedKeys = true, keyProperty = "gbStreamId", keyColumn = "gbStreamId") | |
| 130 | + @Options(useGeneratedKeys = true, keyProperty = "gbStreamId", keyColumn = "gb_stream_id") | |
| 131 | 131 | void batchAdd(List<StreamPushItem> subList); |
| 132 | 132 | |
| 133 | 133 | @Update({"<script>" + |
| 134 | 134 | "<foreach collection='gpsMsgInfos' item='item' separator=';'>" + |
| 135 | 135 | " UPDATE" + |
| 136 | - " gb_stream" + | |
| 136 | + " wvp_gb_stream" + | |
| 137 | 137 | " SET longitude=#{item.lng}, latitude=#{item.lat} " + |
| 138 | - "WHERE gbId=#{item.id}"+ | |
| 138 | + "WHERE gb_id=#{item.id}"+ | |
| 139 | 139 | "</foreach>" + |
| 140 | 140 | "</script>"}) |
| 141 | 141 | int updateStreamGPS(List<GPSMsgInfo> gpsMsgInfos); |
| 142 | 142 | |
| 143 | 143 | @Select("<script> "+ |
| 144 | - "SELECT * FROM gb_stream where " + | |
| 144 | + "SELECT * FROM wvp_gb_stream where " + | |
| 145 | 145 | "<foreach collection='streamPushItems' item='item' separator='or'>" + |
| 146 | 146 | "(app=#{item.app} and stream=#{item.stream}) " + |
| 147 | 147 | "</foreach>" + |
| 148 | 148 | "</script>") |
| 149 | 149 | List<GbStream> selectAllForAppAndStream(List<StreamPushItem> streamPushItems); |
| 150 | 150 | |
| 151 | - @Update("UPDATE gb_stream " + | |
| 152 | - "SET mediaServerId=#{mediaServerId}" + | |
| 151 | + @Update("UPDATE wvp_gb_stream " + | |
| 152 | + "SET media_server_id=#{mediaServerId}" + | |
| 153 | 153 | "WHERE app=#{app} AND stream=#{stream}") |
| 154 | 154 | void updateMediaServer(String app, String stream, String mediaServerId); |
| 155 | 155 | |
| 156 | 156 | @Update("<script> "+ |
| 157 | 157 | " <foreach collection='list' item='item' index='index' separator=';'>"+ |
| 158 | - "UPDATE gb_stream " + | |
| 158 | + "UPDATE wvp_gb_stream " + | |
| 159 | 159 | " SET name=#{item.name},"+ |
| 160 | - " gbId=#{item.gbId}"+ | |
| 160 | + " gb_id=#{item.gb_id}"+ | |
| 161 | 161 | " WHERE app=#{item.app} and stream=#{item.stream}"+ |
| 162 | 162 | "</foreach>"+ |
| 163 | 163 | "</script>") |
| 164 | 164 | int updateGbIdOrName(List<StreamPushItem> streamPushItemForUpdate); |
| 165 | 165 | |
| 166 | - @Select("SELECT status FROM stream_proxy WHERE app=#{app} AND stream=#{stream}") | |
| 166 | + @Select("SELECT status FROM wvp_stream_proxy WHERE app=#{app} AND stream=#{stream}") | |
| 167 | 167 | Boolean selectStatusForProxy(String app, String stream); |
| 168 | 168 | |
| 169 | - @Select("SELECT status FROM stream_push WHERE app=#{app} AND stream=#{stream}") | |
| 169 | + @Select("SELECT status FROM wvp_stream_push WHERE app=#{app} AND stream=#{stream}") | |
| 170 | 170 | Boolean selectStatusForPush(String app, String stream); |
| 171 | 171 | |
| 172 | 172 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/LogMapper.java
| 1 | 1 | package com.genersoft.iot.vmp.storager.dao; |
| 2 | 2 | |
| 3 | -import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; | |
| 4 | 3 | import com.genersoft.iot.vmp.storager.dao.dto.LogDto; |
| 5 | 4 | import org.apache.ibatis.annotations.Delete; |
| 6 | 5 | import org.apache.ibatis.annotations.Insert; |
| ... | ... | @@ -17,21 +16,21 @@ import java.util.List; |
| 17 | 16 | @Repository |
| 18 | 17 | public interface LogMapper { |
| 19 | 18 | |
| 20 | - @Insert("insert into log ( name, type, uri, address, result, timing, username, createTime) " + | |
| 19 | + @Insert("insert into wvp_log ( name,type,uri,address,result,timing,username,create_time) " + | |
| 21 | 20 | "values (#{name}, #{type}, #{uri}, #{address}, #{result}, #{timing}, #{username}, #{createTime})") |
| 22 | 21 | int add(LogDto logDto); |
| 23 | 22 | |
| 24 | 23 | @Select(value = {"<script>" + |
| 25 | - " SELECT * FROM log " + | |
| 24 | + " SELECT * FROM wvp_log " + | |
| 26 | 25 | " WHERE 1=1 " + |
| 27 | 26 | " <if test=\"query != null\"> AND (name LIKE concat('%',#{query},'%'))</if> " + |
| 28 | 27 | " <if test=\"type != null\" > AND type = #{type}</if>" + |
| 29 | - " <if test=\"startTime != null\" > AND createTime >= #{startTime} </if>" + | |
| 30 | - " <if test=\"endTime != null\" > AND createTime <= #{endTime} </if>" + | |
| 31 | - " ORDER BY createTime DESC " + | |
| 28 | + " <if test=\"startTime != null\" > AND create_time >= #{startTime} </if>" + | |
| 29 | + " <if test=\"endTime != null\" > AND create_time <= #{endTime} </if>" + | |
| 30 | + " ORDER BY create_time DESC " + | |
| 32 | 31 | " </script>"}) |
| 33 | 32 | List<LogDto> query(String query, String type, String startTime, String endTime); |
| 34 | 33 | |
| 35 | - @Delete("DELETE FROM log") | |
| 34 | + @Delete("DELETE FROM wvp_log") | |
| 36 | 35 | int clear(); |
| 37 | 36 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
| ... | ... | @@ -11,28 +11,28 @@ import java.util.List; |
| 11 | 11 | @Repository |
| 12 | 12 | public interface MediaServerMapper { |
| 13 | 13 | |
| 14 | - @Insert("INSERT INTO media_server (" + | |
| 15 | - "id, " + | |
| 16 | - "ip, " + | |
| 17 | - "hookIp, " + | |
| 18 | - "sdpIp, " + | |
| 19 | - "streamIp, " + | |
| 20 | - "httpPort, " + | |
| 21 | - "httpSSlPort, " + | |
| 22 | - "rtmpPort, " + | |
| 23 | - "rtmpSSlPort, " + | |
| 24 | - "rtpProxyPort, " + | |
| 25 | - "rtspPort, " + | |
| 26 | - "rtspSSLPort, " + | |
| 27 | - "autoConfig, " + | |
| 28 | - "secret, " + | |
| 29 | - "rtpEnable, " + | |
| 30 | - "rtpPortRange, " + | |
| 31 | - "recordAssistPort, " + | |
| 32 | - "defaultServer, " + | |
| 33 | - "createTime, " + | |
| 34 | - "updateTime, " + | |
| 35 | - "hookAliveInterval" + | |
| 14 | + @Insert("INSERT INTO wvp_media_server (" + | |
| 15 | + "id,"+ | |
| 16 | + "ip,"+ | |
| 17 | + "hook_ip,"+ | |
| 18 | + "sdp_ip,"+ | |
| 19 | + "stream_ip,"+ | |
| 20 | + "http_port,"+ | |
| 21 | + "http_ssl_port,"+ | |
| 22 | + "rtmp_port,"+ | |
| 23 | + "rtmp_ssl_port,"+ | |
| 24 | + "rtp_proxy_port,"+ | |
| 25 | + "rtsp_port,"+ | |
| 26 | + "rtsp_ssl_port,"+ | |
| 27 | + "auto_config,"+ | |
| 28 | + "secret,"+ | |
| 29 | + "rtp_enable,"+ | |
| 30 | + "rtp_port_range,"+ | |
| 31 | + "record_assist_port,"+ | |
| 32 | + "default_server,"+ | |
| 33 | + "create_time,"+ | |
| 34 | + "update_time,"+ | |
| 35 | + "hook_alive_interval"+ | |
| 36 | 36 | ") VALUES " + |
| 37 | 37 | "(" + |
| 38 | 38 | "#{id}, " + |
| ... | ... | @@ -59,70 +59,70 @@ public interface MediaServerMapper { |
| 59 | 59 | int add(MediaServerItem mediaServerItem); |
| 60 | 60 | |
| 61 | 61 | @Update(value = {" <script>" + |
| 62 | - "UPDATE media_server " + | |
| 63 | - "SET updateTime=#{updateTime}" + | |
| 62 | + "UPDATE wvp_media_server " + | |
| 63 | + "SET update_time=#{updateTime}" + | |
| 64 | 64 | "<if test=\"ip != null\">, ip=#{ip}</if>" + |
| 65 | - "<if test=\"hookIp != null\">, hookIp=#{hookIp}</if>" + | |
| 66 | - "<if test=\"sdpIp != null\">, sdpIp=#{sdpIp}</if>" + | |
| 67 | - "<if test=\"streamIp != null\">, streamIp=#{streamIp}</if>" + | |
| 68 | - "<if test=\"httpPort != null\">, httpPort=#{httpPort}</if>" + | |
| 69 | - "<if test=\"httpSSlPort != null\">, httpSSlPort=#{httpSSlPort}</if>" + | |
| 70 | - "<if test=\"rtmpPort != null\">, rtmpPort=#{rtmpPort}</if>" + | |
| 71 | - "<if test=\"rtmpSSlPort != null\">, rtmpSSlPort=#{rtmpSSlPort}</if>" + | |
| 72 | - "<if test=\"rtpProxyPort != null\">, rtpProxyPort=#{rtpProxyPort}</if>" + | |
| 73 | - "<if test=\"rtspPort != null\">, rtspPort=#{rtspPort}</if>" + | |
| 74 | - "<if test=\"rtspSSLPort != null\">, rtspSSLPort=#{rtspSSLPort}</if>" + | |
| 75 | - "<if test=\"autoConfig != null\">, autoConfig=#{autoConfig}</if>" + | |
| 76 | - "<if test=\"rtpEnable != null\">, rtpEnable=#{rtpEnable}</if>" + | |
| 77 | - "<if test=\"rtpPortRange != null\">, rtpPortRange=#{rtpPortRange}</if>" + | |
| 65 | + "<if test=\"hookIp != null\">, hook_ip=#{hookIp}</if>" + | |
| 66 | + "<if test=\"sdpIp != null\">, sdp_ip=#{sdpIp}</if>" + | |
| 67 | + "<if test=\"streamIp != null\">, stream_ip=#{streamIp}</if>" + | |
| 68 | + "<if test=\"httpPort != null\">, http_port=#{httpPort}</if>" + | |
| 69 | + "<if test=\"httpSSlPort != null\">, http_ssl_port=#{httpSSlPort}</if>" + | |
| 70 | + "<if test=\"rtmpPort != null\">, rtmp_port=#{rtmpPort}</if>" + | |
| 71 | + "<if test=\"rtmpSSlPort != null\">, rtmp_ssl_port=#{rtmpSSlPort}</if>" + | |
| 72 | + "<if test=\"rtpProxyPort != null\">, rtp_proxy_port=#{rtpProxyPort}</if>" + | |
| 73 | + "<if test=\"rtspPort != null\">, rtsp_port=#{rtspPort}</if>" + | |
| 74 | + "<if test=\"rtspSSLPort != null\">, rtsp_ssl_port=#{rtspSSLPort}</if>" + | |
| 75 | + "<if test=\"autoConfig != null\">, auto_config=#{autoConfig}</if>" + | |
| 76 | + "<if test=\"rtpEnable != null\">, rtp_enable=#{rtpEnable}</if>" + | |
| 77 | + "<if test=\"rtpPortRange != null\">, rtp_port_range=#{rtpPortRange}</if>" + | |
| 78 | 78 | "<if test=\"secret != null\">, secret=#{secret}</if>" + |
| 79 | - "<if test=\"recordAssistPort != null\">, recordAssistPort=#{recordAssistPort}</if>" + | |
| 80 | - "<if test=\"hookAliveInterval != null\">, hookAliveInterval=#{hookAliveInterval}</if>" + | |
| 79 | + "<if test=\"recordAssistPort != null\">, record_assist_port=#{recordAssistPort}</if>" + | |
| 80 | + "<if test=\"hookAliveInterval != null\">, hook_alive_interval=#{hookAliveInterval}</if>" + | |
| 81 | 81 | "WHERE id=#{id}"+ |
| 82 | 82 | " </script>"}) |
| 83 | 83 | int update(MediaServerItem mediaServerItem); |
| 84 | 84 | |
| 85 | 85 | @Update(value = {" <script>" + |
| 86 | - "UPDATE media_server " + | |
| 87 | - "SET updateTime=#{updateTime}" + | |
| 86 | + "UPDATE wvp_media_server " + | |
| 87 | + "SET update_time=#{updateTime}" + | |
| 88 | 88 | "<if test=\"id != null\">, id=#{id}</if>" + |
| 89 | - "<if test=\"hookIp != null\">, hookIp=#{hookIp}</if>" + | |
| 90 | - "<if test=\"sdpIp != null\">, sdpIp=#{sdpIp}</if>" + | |
| 91 | - "<if test=\"streamIp != null\">, streamIp=#{streamIp}</if>" + | |
| 92 | - "<if test=\"httpSSlPort != null\">, httpSSlPort=#{httpSSlPort}</if>" + | |
| 93 | - "<if test=\"rtmpPort != null\">, rtmpPort=#{rtmpPort}</if>" + | |
| 94 | - "<if test=\"rtmpSSlPort != null\">, rtmpSSlPort=#{rtmpSSlPort}</if>" + | |
| 95 | - "<if test=\"rtpProxyPort != null\">, rtpProxyPort=#{rtpProxyPort}</if>" + | |
| 96 | - "<if test=\"rtspPort != null\">, rtspPort=#{rtspPort}</if>" + | |
| 97 | - "<if test=\"rtspSSLPort != null\">, rtspSSLPort=#{rtspSSLPort}</if>" + | |
| 98 | - "<if test=\"autoConfig != null\">, autoConfig=#{autoConfig}</if>" + | |
| 99 | - "<if test=\"rtpEnable != null\">, rtpEnable=#{rtpEnable}</if>" + | |
| 100 | - "<if test=\"rtpPortRange != null\">, rtpPortRange=#{rtpPortRange}</if>" + | |
| 89 | + "<if test=\"hookIp != null\">, hook_ip=#{hookIp}</if>" + | |
| 90 | + "<if test=\"sdpIp != null\">, sdp_ip=#{sdpIp}</if>" + | |
| 91 | + "<if test=\"streamIp != null\">, stream_ip=#{streamIp}</if>" + | |
| 92 | + "<if test=\"httpSSlPort != null\">, http_ssl_port=#{httpSSlPort}</if>" + | |
| 93 | + "<if test=\"rtmpPort != null\">, rtmp_port=#{rtmpPort}</if>" + | |
| 94 | + "<if test=\"rtmpSSlPort != null\">, rtmp_ssl_port=#{rtmpSSlPort}</if>" + | |
| 95 | + "<if test=\"rtpProxyPort != null\">, rtp_proxy_port=#{rtpProxyPort}</if>" + | |
| 96 | + "<if test=\"rtspPort != null\">, rtsp_port=#{rtspPort}</if>" + | |
| 97 | + "<if test=\"rtspSSLPort != null\">, rtsp_ssl_port=#{rtspSSLPort}</if>" + | |
| 98 | + "<if test=\"autoConfig != null\">, auto_config=#{autoConfig}</if>" + | |
| 99 | + "<if test=\"rtpEnable != null\">, rtp_enable=#{rtpEnable}</if>" + | |
| 100 | + "<if test=\"rtpPortRange != null\">, rtp_port_range=#{rtpPortRange}</if>" + | |
| 101 | 101 | "<if test=\"secret != null\">, secret=#{secret}</if>" + |
| 102 | - "<if test=\"recordAssistPort != null\">, recordAssistPort=#{recordAssistPort}</if>" + | |
| 103 | - "<if test=\"hookAliveInterval != null\">, hookAliveInterval=#{hookAliveInterval}</if>" + | |
| 104 | - "WHERE ip=#{ip} and httpPort=#{httpPort}"+ | |
| 102 | + "<if test=\"recordAssistPort != null\">, record_assist_port=#{recordAssistPort}</if>" + | |
| 103 | + "<if test=\"hookAliveInterval != null\">, hook_alive_interval=#{hookAliveInterval}</if>" + | |
| 104 | + "WHERE ip=#{ip} and http_port=#{httpPort}"+ | |
| 105 | 105 | " </script>"}) |
| 106 | 106 | int updateByHostAndPort(MediaServerItem mediaServerItem); |
| 107 | 107 | |
| 108 | - @Select("SELECT * FROM media_server WHERE id=#{id}") | |
| 108 | + @Select("SELECT * FROM wvp_media_server WHERE id=#{id}") | |
| 109 | 109 | MediaServerItem queryOne(String id); |
| 110 | 110 | |
| 111 | - @Select("SELECT * FROM media_server") | |
| 111 | + @Select("SELECT * FROM wvp_media_server") | |
| 112 | 112 | List<MediaServerItem> queryAll(); |
| 113 | 113 | |
| 114 | - @Delete("DELETE FROM media_server WHERE id=#{id}") | |
| 114 | + @Delete("DELETE FROM wvp_media_server WHERE id=#{id}") | |
| 115 | 115 | void delOne(String id); |
| 116 | 116 | |
| 117 | - @Select("DELETE FROM media_server WHERE ip=#{host} and httpPort=#{port}") | |
| 117 | + @Select("DELETE FROM wvp_media_server WHERE ip=#{host} and http_port=#{port}") | |
| 118 | 118 | void delOneByIPAndPort(String host, int port); |
| 119 | 119 | |
| 120 | - @Delete("DELETE FROM media_server WHERE defaultServer=1") | |
| 120 | + @Delete("DELETE FROM wvp_media_server WHERE default_server=true") | |
| 121 | 121 | int delDefault(); |
| 122 | 122 | |
| 123 | - @Select("SELECT * FROM media_server WHERE ip=#{host} and httpPort=#{port}") | |
| 123 | + @Select("SELECT * FROM wvp_media_server WHERE ip=#{host} and http_port=#{port}") | |
| 124 | 124 | MediaServerItem queryOneByHostAndPort(String host, int port); |
| 125 | 125 | |
| 126 | - @Select("SELECT * FROM media_server WHERE defaultServer=1") | |
| 126 | + @Select("SELECT * FROM wvp_media_server WHERE default_server=true") | |
| 127 | 127 | MediaServerItem queryDefault(); |
| 128 | 128 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
| ... | ... | @@ -14,88 +14,87 @@ import java.util.List; |
| 14 | 14 | @Repository |
| 15 | 15 | public interface ParentPlatformMapper { |
| 16 | 16 | |
| 17 | - @Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp, " + | |
| 18 | - " devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, asMessageChannel, " + | |
| 19 | - " status, startOfflinePush, catalogId, administrativeDivision, catalogGroup, createTime, updateTime, treeType) " + | |
| 17 | + @Insert("INSERT INTO wvp_platform (enable, name, server_gb_id, server_gb_domain, server_ip, server_port,device_gb_id,device_ip,"+ | |
| 18 | + "device_port,username,password,expires,keep_timeout,transport,character_set,ptz,rtcp,as_message_channel,"+ | |
| 19 | + "status,start_offline_push,catalog_id,administrative_division,catalog_group,create_time,update_time) " + | |
| 20 | 20 | " VALUES (#{enable}, #{name}, #{serverGBId}, #{serverGBDomain}, #{serverIP}, #{serverPort}, #{deviceGBId}, #{deviceIp}, " + |
| 21 | 21 | " #{devicePort}, #{username}, #{password}, #{expires}, #{keepTimeout}, #{transport}, #{characterSet}, #{ptz}, #{rtcp}, #{asMessageChannel}, " + |
| 22 | - " #{status}, #{startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime}, #{treeType})") | |
| 22 | + " #{status}, #{startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime})") | |
| 23 | 23 | int addParentPlatform(ParentPlatform parentPlatform); |
| 24 | 24 | |
| 25 | - @Update("UPDATE parent_platform " + | |
| 25 | + @Update("UPDATE wvp_platform " + | |
| 26 | 26 | "SET enable=#{enable}, " + |
| 27 | 27 | "name=#{name}," + |
| 28 | - "deviceGBId=#{deviceGBId}," + | |
| 29 | - "serverGBId=#{serverGBId}, " + | |
| 30 | - "serverGBDomain=#{serverGBDomain}, " + | |
| 31 | - "serverIP=#{serverIP}," + | |
| 32 | - "serverPort=#{serverPort}, " + | |
| 33 | - "deviceIp=#{deviceIp}, " + | |
| 34 | - "devicePort=#{devicePort}, " + | |
| 28 | + "device_gb_id=#{deviceGBId}," + | |
| 29 | + "server_gb_id=#{serverGBId}, " + | |
| 30 | + "server_gb_domain=#{serverGBDomain}, " + | |
| 31 | + "server_ip=#{serverIP}," + | |
| 32 | + "server_port=#{serverPort}, " + | |
| 33 | + "device_ip=#{deviceIp}, " + | |
| 34 | + "device_port=#{devicePort}, " + | |
| 35 | 35 | "username=#{username}, " + |
| 36 | 36 | "password=#{password}, " + |
| 37 | 37 | "expires=#{expires}, " + |
| 38 | - "keepTimeout=#{keepTimeout}, " + | |
| 38 | + "keep_timeout=#{keepTimeout}, " + | |
| 39 | 39 | "transport=#{transport}, " + |
| 40 | - "characterSet=#{characterSet}, " + | |
| 40 | + "character_set=#{characterSet}, " + | |
| 41 | 41 | "ptz=#{ptz}, " + |
| 42 | 42 | "rtcp=#{rtcp}, " + |
| 43 | - "asMessageChannel=#{asMessageChannel}, " + | |
| 43 | + "as_message_channel=#{asMessageChannel}, " + | |
| 44 | 44 | "status=#{status}, " + |
| 45 | - "startOfflinePush=#{startOfflinePush}, " + | |
| 46 | - "catalogGroup=#{catalogGroup}, " + | |
| 47 | - "administrativeDivision=#{administrativeDivision}, " + | |
| 48 | - "createTime=#{createTime}, " + | |
| 49 | - "updateTime=#{updateTime}, " + | |
| 50 | - "treeType=#{treeType}, " + | |
| 51 | - "catalogId=#{catalogId} " + | |
| 45 | + "start_offline_push=#{startOfflinePush}, " + | |
| 46 | + "catalog_group=#{catalogGroup}, " + | |
| 47 | + "administrative_division=#{administrativeDivision}, " + | |
| 48 | + "create_time=#{createTime}, " + | |
| 49 | + "update_time=#{updateTime}, " + | |
| 50 | + "catalog_id=#{catalogId} " + | |
| 52 | 51 | "WHERE id=#{id}") |
| 53 | 52 | int updateParentPlatform(ParentPlatform parentPlatform); |
| 54 | 53 | |
| 55 | - @Delete("DELETE FROM parent_platform WHERE serverGBId=#{serverGBId}") | |
| 54 | + @Delete("DELETE FROM wvp_platform WHERE server_gb_id=#{serverGBId}") | |
| 56 | 55 | int delParentPlatform(ParentPlatform parentPlatform); |
| 57 | 56 | |
| 58 | 57 | @Select("SELECT *, ((SELECT count(0)\n" + |
| 59 | - " FROM platform_gb_channel pc\n" + | |
| 60 | - " WHERE pc.platformId = pp.serverGBId)\n" + | |
| 58 | + " FROM wvp_platform_gb_channel pc\n" + | |
| 59 | + " WHERE pc.platform_id = pp.server_gb_id)\n" + | |
| 61 | 60 | " +\n" + |
| 62 | 61 | " (SELECT count(0)\n" + |
| 63 | - " FROM platform_gb_stream pgs\n" + | |
| 64 | - " WHERE pgs.platformId = pp.serverGBId)\n" + | |
| 62 | + " FROM wvp_platform_gb_stream pgs\n" + | |
| 63 | + " WHERE pgs.platform_id = pp.server_gb_id)\n" + | |
| 65 | 64 | " +\n" + |
| 66 | 65 | " (SELECT count(0)\n" + |
| 67 | - " FROM platform_catalog pgc\n" + | |
| 68 | - " WHERE pgc.platformId = pp.serverGBId)) as channelCount\n" + | |
| 69 | - "FROM parent_platform pp ") | |
| 66 | + " FROM wvp_platform_catalog pgc\n" + | |
| 67 | + " WHERE pgc.platform_id = pp.server_gb_id)) as channel_count\n" + | |
| 68 | + "FROM wvp_platform pp ") | |
| 70 | 69 | List<ParentPlatform> getParentPlatformList(); |
| 71 | 70 | |
| 72 | - @Select("SELECT * FROM parent_platform WHERE enable=#{enable} ") | |
| 71 | + @Select("SELECT * FROM wvp_platform WHERE enable=#{enable} ") | |
| 73 | 72 | List<ParentPlatform> getEnableParentPlatformList(boolean enable); |
| 74 | 73 | |
| 75 | - @Select("SELECT * FROM parent_platform WHERE enable=1 and asMessageChannel = 1") | |
| 74 | + @Select("SELECT * FROM wvp_platform WHERE enable=true and as_message_channel=true") | |
| 76 | 75 | List<ParentPlatform> queryEnablePlatformListWithAsMessageChannel(); |
| 77 | 76 | |
| 78 | - @Select("SELECT * FROM parent_platform WHERE serverGBId=#{platformGbId}") | |
| 77 | + @Select("SELECT * FROM wvp_platform WHERE server_gb_id=#{platformGbId}") | |
| 79 | 78 | ParentPlatform getParentPlatByServerGBId(String platformGbId); |
| 80 | 79 | |
| 81 | - @Select("SELECT * FROM parent_platform WHERE id=#{id}") | |
| 80 | + @Select("SELECT * FROM wvp_platform WHERE id=#{id}") | |
| 82 | 81 | ParentPlatform getParentPlatById(int id); |
| 83 | 82 | |
| 84 | - @Update("UPDATE parent_platform SET status=false" ) | |
| 83 | + @Update("UPDATE wvp_platform SET status=false" ) | |
| 85 | 84 | int outlineForAllParentPlatform(); |
| 86 | 85 | |
| 87 | - @Update("UPDATE parent_platform SET status=#{online} WHERE serverGBId=#{platformGbID}" ) | |
| 86 | + @Update("UPDATE wvp_platform SET status=#{online} WHERE server_gb_id=#{platformGbID}" ) | |
| 88 | 87 | int updateParentPlatformStatus(String platformGbID, boolean online); |
| 89 | 88 | |
| 90 | 89 | @Update(value = {" <script>" + |
| 91 | - "UPDATE parent_platform " + | |
| 92 | - "SET catalogId=#{catalogId}, updateTime=#{updateTime}" + | |
| 93 | - "WHERE serverGBId=#{platformId}"+ | |
| 90 | + "UPDATE wvp_platform " + | |
| 91 | + "SET catalog_id=#{catalogId}, update_time=#{updateTime}" + | |
| 92 | + "WHERE server_gb_id=#{platformId}"+ | |
| 94 | 93 | "</script>"}) |
| 95 | 94 | int setDefaultCatalog(String platformId, String catalogId, String updateTime); |
| 96 | 95 | |
| 97 | - @Select("select 'channel' as name, count(pgc.platformId) count from platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId where pgc.platformId=#{platformId} and dc.channelId =#{gbId} " + | |
| 96 | + @Select("select 'channel' as name, count(pgc.platform_id) count from wvp_platform_gb_channel pgc left join wvp_device_channel dc on dc.id = pgc.device_channel_id where pgc.platform_id=#{platform_id} and dc.channel_id =#{gbId} " + | |
| 98 | 97 | "union " + |
| 99 | - "select 'stream' as name, count(pgs.platformId) count from platform_gb_stream pgs left join gb_stream gs on pgs.gbStreamId = gs.gbStreamId where pgs.platformId=#{platformId} and gs.gbId = #{gbId}") | |
| 100 | - List<ChannelSourceInfo> getChannelSource(String platformId, String gbId); | |
| 98 | + "select 'stream' as name, count(pgs.platform_id) count from wvp_platform_gb_stream pgs left join wvp_gb_stream gs on pgs.gb_stream_id = gs.gb_stream_id where pgs.platform_id=#{platform_id} and gs.gb_id =#{gbId}") | |
| 99 | + List<ChannelSourceInfo> getChannelSource(String platform_id, String gbId); | |
| 101 | 100 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java
| 1 | 1 | package com.genersoft.iot.vmp.storager.dao; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 4 | -import com.genersoft.iot.vmp.gb28181.bean.GbStream; | |
| 5 | 4 | import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog; |
| 6 | -import com.genersoft.iot.vmp.gb28181.bean.PlatformGbStream; | |
| 7 | -import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; | |
| 8 | 5 | import org.apache.ibatis.annotations.*; |
| 9 | 6 | import org.springframework.stereotype.Repository; |
| 10 | 7 | |
| ... | ... | @@ -15,42 +12,43 @@ import java.util.List; |
| 15 | 12 | @Repository |
| 16 | 13 | public interface PlatformCatalogMapper { |
| 17 | 14 | |
| 18 | - @Insert("INSERT INTO platform_catalog (id, name, platformId, parentId, civilCode, businessGroupId) VALUES" + | |
| 15 | + @Insert("INSERT INTO wvp_platform_catalog (id, name, platform_id, parent_id, civil_code, business_group_id) VALUES" + | |
| 19 | 16 | "(#{id}, #{name}, #{platformId}, #{parentId}, #{civilCode}, #{businessGroupId})") |
| 20 | 17 | int add(PlatformCatalog platformCatalog); |
| 21 | 18 | |
| 22 | - @Delete("DELETE FROM platform_catalog WHERE id=#{id}") | |
| 19 | + @Delete("DELETE from wvp_platform_catalog WHERE id=#{id}") | |
| 23 | 20 | int del(String id); |
| 24 | 21 | |
| 25 | - @Delete("DELETE FROM platform_catalog WHERE platformId=#{platformId}") | |
| 22 | + @Delete("DELETE from wvp_platform_catalog WHERE platform_id=#{platformId}") | |
| 26 | 23 | int delByPlatformId(String platformId); |
| 27 | 24 | |
| 28 | - @Select("SELECT pc.*, count(pc2.id) as childrenCount FROM platform_catalog pc " + | |
| 29 | - "left join platform_catalog pc2 on pc.id = pc2.parentId " + | |
| 30 | - "WHERE pc.parentId=#{parentId} AND pc.platformId=#{platformId} group by pc.id") | |
| 25 | + @Select("SELECT pc.*, count(pc2.id) as children_count from wvp_platform_catalog pc " + | |
| 26 | + "left join wvp_platform_catalog pc2 on pc.id = pc2.parent_id " + | |
| 27 | + "WHERE pc.parent_id=#{parentId} AND pc.platform_id=#{platformId} " + | |
| 28 | + "group by pc.id, pc.name, pc.platform_id, pc.business_group_id, pc.civil_code, pc.parent_id") | |
| 31 | 29 | List<PlatformCatalog> selectByParentId(String platformId, String parentId); |
| 32 | 30 | |
| 33 | - @Select("SELECT *, (SELECT COUNT(1) from platform_catalog where parentId = pc.id) as childrenCount FROM platform_catalog pc WHERE pc.id=#{id}") | |
| 31 | + @Select("SELECT *, (SELECT COUNT(1) from wvp_platform_catalog where parent_id = pc.id) as children_count from wvp_platform_catalog pc WHERE pc.id=#{id}") | |
| 34 | 32 | PlatformCatalog select(String id); |
| 35 | 33 | |
| 36 | 34 | @Update(value = {" <script>" + |
| 37 | - "UPDATE platform_catalog " + | |
| 35 | + "UPDATE wvp_platform_catalog " + | |
| 38 | 36 | "SET name=#{name}" + |
| 39 | 37 | "WHERE id=#{id}"+ |
| 40 | 38 | "</script>"}) |
| 41 | 39 | int update(PlatformCatalog platformCatalog); |
| 42 | 40 | |
| 43 | - @Select("SELECT *, (SELECT COUNT(1) from platform_catalog where parentId = pc.id) as childrenCount FROM platform_catalog pc WHERE pc.platformId=#{platformId}") | |
| 41 | + @Select("SELECT *, (SELECT COUNT(1) from wvp_platform_catalog where parent_id = pc.id) as children_count from wvp_platform_catalog pc WHERE pc.platform_id=#{platformId}") | |
| 44 | 42 | List<PlatformCatalog> selectByPlatForm(String platformId); |
| 45 | 43 | |
| 46 | - @Select("SELECT pc.* FROM platform_catalog pc WHERE pc.id = (SELECT pp.catalogId from parent_platform pp WHERE pp.serverGBId=#{platformId})") | |
| 44 | + @Select("SELECT pc.* FROM wvp_platform_catalog pc WHERE pc.id = (SELECT pp.catalog_id from wvp_platform pp WHERE pp.server_gb_id=#{platformId})") | |
| 47 | 45 | PlatformCatalog selectDefaultByPlatFormId(String platformId); |
| 48 | 46 | |
| 49 | 47 | |
| 50 | - @Select("SELECT pc.* FROM platform_catalog pc WHERE pc.id = #{id}") | |
| 48 | + @Select("SELECT pc.* FROM wvp_platform_catalog pc WHERE pc.id = #{id}") | |
| 51 | 49 | PlatformCatalog selectParentCatalog(String id); |
| 52 | 50 | |
| 53 | - @Select("SELECT pc.id as channelId, pc.name, pc.civilCode, pc.businessGroupId,'1' as parental, pc.parentId " + | |
| 54 | - " FROM platform_catalog pc WHERE pc.platformId=#{platformId}") | |
| 51 | + @Select("SELECT pc.id as channel_id, pc.name, pc.civil_code, pc.business_group_id,'1' as parental, pc.parent_id " + | |
| 52 | + " from wvp_platform_catalog pc WHERE pc.platform_id=#{platformId}") | |
| 55 | 53 | List<DeviceChannel> queryCatalogInPlatform(String platformId); |
| 56 | 54 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
| ... | ... | @@ -21,13 +21,13 @@ public interface PlatformChannelMapper { |
| 21 | 21 | * 查询列表里已经关联的 |
| 22 | 22 | */ |
| 23 | 23 | @Select("<script> "+ |
| 24 | - "SELECT deviceChannelId FROM platform_gb_channel WHERE platformId=#{platformId} AND deviceChannelId in" + | |
| 24 | + "SELECT device_channel_id from wvp_platform_gb_channel WHERE platform_id=#{platformId} AND device_channel_id in" + | |
| 25 | 25 | "<foreach collection='channelReduces' open='(' item='item' separator=',' close=')'> #{item.id}</foreach>" + |
| 26 | 26 | "</script>") |
| 27 | 27 | List<Integer> findChannelRelatedPlatform(String platformId, List<ChannelReduce> channelReduces); |
| 28 | 28 | |
| 29 | 29 | @Insert("<script> "+ |
| 30 | - "INSERT INTO platform_gb_channel (platformId, deviceChannelId, catalogId) VALUES" + | |
| 30 | + "INSERT INTO wvp_platform_gb_channel (platform_id, device_channel_id, catalog_id) VALUES" + | |
| 31 | 31 | "<foreach collection='channelReducesToAdd' item='item' separator=','>" + |
| 32 | 32 | " (#{platformId}, #{item.id} , #{item.catalogId} )" + |
| 33 | 33 | "</foreach>" + |
| ... | ... | @@ -35,50 +35,50 @@ public interface PlatformChannelMapper { |
| 35 | 35 | int addChannels(String platformId, List<ChannelReduce> channelReducesToAdd); |
| 36 | 36 | |
| 37 | 37 | @Delete("<script> "+ |
| 38 | - "DELETE FROM platform_gb_channel WHERE platformId=#{platformId} AND deviceChannelId in" + | |
| 38 | + "DELETE from wvp_platform_gb_channel WHERE platform_id=#{platformId} AND device_channel_id in" + | |
| 39 | 39 | "<foreach collection='channelReducesToDel' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" + |
| 40 | 40 | "</script>") |
| 41 | 41 | int delChannelForGB(String platformId, List<ChannelReduce> channelReducesToDel); |
| 42 | 42 | |
| 43 | 43 | @Delete("<script> "+ |
| 44 | - "DELETE FROM platform_gb_channel WHERE deviceChannelId in " + | |
| 45 | - "( select temp.deviceChannelId from " + | |
| 46 | - "(select pgc.deviceChannelId from platform_gb_channel pgc " + | |
| 47 | - "left join device_channel dc on dc.id = pgc.deviceChannelId where dc.deviceId =#{deviceId} " + | |
| 44 | + "DELETE from wvp_platform_gb_channel WHERE device_channel_id in " + | |
| 45 | + "( select temp.device_channel_id from " + | |
| 46 | + "(select pgc.device_channel_id from wvp_platform_gb_channel pgc " + | |
| 47 | + "left join wvp_device_channel dc on dc.id = pgc.device_channel_id where dc.device_id =#{deviceId} " + | |
| 48 | 48 | ") temp)" + |
| 49 | 49 | "</script>") |
| 50 | 50 | int delChannelForDeviceId(String deviceId); |
| 51 | 51 | |
| 52 | 52 | @Delete("<script> "+ |
| 53 | - "DELETE FROM platform_gb_channel WHERE platformId=#{platformId}" + | |
| 53 | + "DELETE from wvp_platform_gb_channel WHERE platform_id=#{platformId}" + | |
| 54 | 54 | "</script>") |
| 55 | 55 | int cleanChannelForGB(String platformId); |
| 56 | 56 | |
| 57 | - @Select("SELECT dc.* FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE dc.channelId=#{channelId} and pgc.platformId=#{platformId}") | |
| 57 | + @Select("SELECT dc.* from wvp_platform_gb_channel pgc left join wvp_device_channel dc on dc.id = pgc.device_channel_id WHERE dc.channel_id=#{channelId} and pgc.platform_id=#{platformId}") | |
| 58 | 58 | List<DeviceChannel> queryChannelInParentPlatform(String platformId, String channelId); |
| 59 | 59 | |
| 60 | - @Select("SELECT dc.* FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE pgc.platformId=#{platformId} and pgc.catalogId=#{catalogId}") | |
| 60 | + @Select("SELECT dc.* from wvp_platform_gb_channel pgc left join wvp_device_channel dc on dc.id = pgc.device_channel_id WHERE pgc.platform_id=#{platformId} and pgc.catalog_id=#{catalogId}") | |
| 61 | 61 | List<DeviceChannel> queryAllChannelInCatalog(String platformId, String catalogId); |
| 62 | 62 | |
| 63 | - @Select(" select dc.channelId as id, dc.name as name, pgc.platformId as platformId, pgc.catalogId as parentId, 0 as childrenCount, 1 as type " + | |
| 64 | - " from device_channel dc left join platform_gb_channel pgc on dc.id = pgc.deviceChannelId " + | |
| 65 | - " where pgc.platformId=#{platformId} and pgc.catalogId=#{catalogId}") | |
| 63 | + @Select(" select dc.channel_id as id, dc.name as name, pgc.platform_id as platform_id, pgc.catalog_id as parent_id, 0 as children_count, 1 as type " + | |
| 64 | + " from wvp_device_channel dc left join wvp_platform_gb_channel pgc on dc.id = pgc.device_channel_id " + | |
| 65 | + " where pgc.platform_id=#{platformId} and pgc.catalog_id=#{catalogId}") | |
| 66 | 66 | List<PlatformCatalog> queryChannelInParentPlatformAndCatalog(String platformId, String catalogId); |
| 67 | 67 | |
| 68 | 68 | @Select("select d.*\n" + |
| 69 | - "from platform_gb_channel pgc\n" + | |
| 70 | - " left join device_channel dc on dc.id = pgc.deviceChannelId\n" + | |
| 71 | - " left join device d on dc.deviceId = d.deviceId\n" + | |
| 72 | - "where dc.channelId = #{channelId} and pgc.platformId=#{platformId}") | |
| 69 | + "from wvp_platform_gb_channel pgc\n" + | |
| 70 | + " left join wvp_device_channel dc on dc.id = pgc.device_channel_id\n" + | |
| 71 | + " left join wvp_device d on dc.device_id = d.device_id\n" + | |
| 72 | + "where dc.channel_id = #{channelId} and pgc.platform_id=#{platformId}") | |
| 73 | 73 | List<Device> queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId); |
| 74 | 74 | |
| 75 | 75 | @Delete("<script> "+ |
| 76 | - "DELETE FROM platform_gb_channel WHERE catalogId=#{id}" + | |
| 76 | + "DELETE from wvp_platform_gb_channel WHERE catalog_id=#{id}" + | |
| 77 | 77 | "</script>") |
| 78 | 78 | int delByCatalogId(String id); |
| 79 | 79 | |
| 80 | 80 | @Delete("<script> "+ |
| 81 | - "DELETE FROM platform_gb_channel WHERE catalogId=#{parentId} AND platformId=#{platformId} AND channelId=#{id}" + | |
| 81 | + "DELETE from wvp_platform_gb_channel WHERE catalog_id=#{parentId} AND platform_id=#{platformId} AND channel_id=#{id}" + | |
| 82 | 82 | "</script>") |
| 83 | 83 | int delByCatalogIdAndChannelIdAndPlatformId(PlatformCatalog platformCatalog); |
| 84 | 84 | |
| ... | ... | @@ -86,35 +86,35 @@ public interface PlatformChannelMapper { |
| 86 | 86 | "SELECT " + |
| 87 | 87 | "pp.* " + |
| 88 | 88 | "FROM " + |
| 89 | - "parent_platform pp " + | |
| 90 | - "left join platform_gb_channel pgc on " + | |
| 91 | - "pp.serverGBId = pgc.platformId " + | |
| 92 | - "left join device_channel dc on " + | |
| 93 | - "dc.id = pgc.deviceChannelId " + | |
| 89 | + "wvp_platform pp " + | |
| 90 | + "left join wvp_platform_gb_channel pgc on " + | |
| 91 | + "pp.server_gb_id = pgc.platform_id " + | |
| 92 | + "left join wvp_device_channel dc on " + | |
| 93 | + "dc.id = pgc.device_channel_id " + | |
| 94 | 94 | "WHERE " + |
| 95 | - "dc.channelId = #{channelId} and pp.status = true " + | |
| 96 | - "AND pp.serverGBId IN" + | |
| 97 | - "<foreach collection='platforms' item='item' open='(' separator=',' close=')' > #{item}</foreach>" + | |
| 95 | + "dc.channel_id = #{channelId} and pp.status = true " + | |
| 96 | + "AND pp.server_gb_id IN" + | |
| 97 | + "<foreach collection='platforms' item='item' open='(' separator=',' close=')' > #{item}</foreach>" + | |
| 98 | 98 | "</script> ") |
| 99 | 99 | List<ParentPlatform> queryPlatFormListForGBWithGBId(String channelId, List<String> platforms); |
| 100 | 100 | |
| 101 | 101 | @Delete("<script> " + |
| 102 | - "DELETE FROM platform_gb_channel WHERE platformId=#{serverGBId}" + | |
| 102 | + "DELETE from wvp_platform_gb_channel WHERE platform_id=#{serverGBId}" + | |
| 103 | 103 | "</script>") |
| 104 | 104 | void delByPlatformId(String serverGBId); |
| 105 | 105 | |
| 106 | 106 | @Delete("<script> " + |
| 107 | - "DELETE FROM platform_gb_channel WHERE platformId=#{platformId} and catalogId=#{catalogId}" + | |
| 107 | + "DELETE from wvp_platform_gb_channel WHERE platform_id=#{platformId} and catalog_id=#{catalogId}" + | |
| 108 | 108 | "</script>") |
| 109 | 109 | int delChannelForGBByCatalogId(String platformId, String catalogId); |
| 110 | 110 | |
| 111 | - @Select("select dc.channelId deviceId,dc.name,d.manufacturer,d.model,d.firmware\n" + | |
| 112 | - "from platform_gb_channel pgc\n" + | |
| 113 | - " left join device_channel dc on dc.id = pgc.deviceChannelId\n" + | |
| 114 | - " left join device d on dc.deviceId = d.deviceId\n" + | |
| 115 | - "where dc.channelId = #{channelId} and pgc.platformId=#{platformId}") | |
| 111 | + @Select("select dc.channel_id dc.device_id,dc.name,d.manufacturer,d.model,d.firmware\n" + | |
| 112 | + "from wvp_platform_gb_channel pgc\n" + | |
| 113 | + " left join wvp_device_channel dc on dc.id = pgc.device_channel_id\n" + | |
| 114 | + " left join wvp_device d on dc.device_id = d.device_id\n" + | |
| 115 | + "where dc.channel_id = #{channelId} and pgc.platform_id=#{platformId}") | |
| 116 | 116 | List<Device> queryDeviceInfoByPlatformIdAndChannelId(String platformId, String channelId); |
| 117 | 117 | |
| 118 | - @Select("SELECT pgc.platformId FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE dc.channelId='${channelId}'") | |
| 118 | + @Select("SELECT pgc.platform_id from wvp_platform_gb_channel pgc left join wvp_device_channel dc on dc.id = pgc.device_channel_id WHERE dc.channel_id='${channelId}'") | |
| 119 | 119 | List<String> queryParentPlatformByChannelId(String channelId); |
| 120 | 120 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java
| ... | ... | @@ -16,82 +16,82 @@ import java.util.List; |
| 16 | 16 | @Repository |
| 17 | 17 | public interface PlatformGbStreamMapper { |
| 18 | 18 | |
| 19 | - @Insert("REPLACE INTO platform_gb_stream (gbStreamId, platformId, catalogId) VALUES" + | |
| 19 | + @Insert("REPLACE INTO wvp_platform_gb_stream (gb_stream_id, platform_id, catalog_id) VALUES" + | |
| 20 | 20 | "( #{gbStreamId}, #{platformId}, #{catalogId})") |
| 21 | 21 | int add(PlatformGbStream platformGbStream); |
| 22 | 22 | |
| 23 | 23 | |
| 24 | 24 | @Insert("<script> " + |
| 25 | - "INSERT into platform_gb_stream " + | |
| 26 | - "(gbStreamId, platformId, catalogId) " + | |
| 25 | + "INSERT into wvp_platform_gb_stream " + | |
| 26 | + "(gb_stream_id, platform_id, catalog_id) " + | |
| 27 | 27 | "values " + |
| 28 | 28 | "<foreach collection='streamPushItems' index='index' item='item' separator=','> " + |
| 29 | - "(#{item.gbStreamId}, #{item.platformId}, #{item.catalogId})" + | |
| 29 | + "(#{item.gbStreamId}, #{item.platform_id}, #{item.catalogId})" + | |
| 30 | 30 | "</foreach> " + |
| 31 | 31 | "</script>") |
| 32 | 32 | int batchAdd(List<StreamPushItem> streamPushItems); |
| 33 | 33 | |
| 34 | - @Delete("DELETE FROM platform_gb_stream WHERE gbStreamId = (select gbStreamId from gb_stream where app=#{app} AND stream=#{stream})") | |
| 34 | + @Delete("DELETE from wvp_platform_gb_stream WHERE gb_stream_id = (select gb_stream_id from wvp_gb_stream where app=#{app} AND stream=#{stream})") | |
| 35 | 35 | int delByAppAndStream(String app, String stream); |
| 36 | 36 | |
| 37 | - @Delete("DELETE FROM platform_gb_stream WHERE platformId=#{platformId}") | |
| 37 | + @Delete("DELETE from wvp_platform_gb_stream WHERE platform_id=#{platformId}") | |
| 38 | 38 | int delByPlatformId(String platformId); |
| 39 | 39 | |
| 40 | 40 | @Select("SELECT " + |
| 41 | 41 | "pp.* " + |
| 42 | 42 | "FROM " + |
| 43 | - "platform_gb_stream pgs " + | |
| 44 | - "LEFT JOIN parent_platform pp ON pp.serverGBId = pgs.platformId " + | |
| 45 | - "LEFT JOIN gb_stream gs ON gs.gbStreamId = pgs.gbStreamId " + | |
| 43 | + "wvp_platform_gb_stream pgs " + | |
| 44 | + "LEFT JOIN wvp_platform pp ON pp.server_gb_id = pgs.platform_id " + | |
| 45 | + "LEFT join wvp_gb_stream gs ON gs.gb_stream_id = pgs.gb_stream_id " + | |
| 46 | 46 | "WHERE " + |
| 47 | 47 | "gs.app =#{app} " + |
| 48 | 48 | "AND gs.stream =#{stream} ") |
| 49 | 49 | List<ParentPlatform> selectByAppAndStream(String app, String stream); |
| 50 | 50 | |
| 51 | - @Select("SELECT pgs.*, gs.gbId FROM platform_gb_stream pgs " + | |
| 52 | - "LEFT JOIN gb_stream gs ON pgs.gbStreamId = gs.gbStreamId " + | |
| 53 | - "WHERE gs.app=#{app} AND gs.stream=#{stream} AND pgs.platformId=#{serverGBId}") | |
| 51 | + @Select("SELECT pgs.*, gs.gb_id from wvp_platform_gb_stream pgs " + | |
| 52 | + "LEFT join wvp_gb_stream gs ON pgs.gb_stream_id = gs.gb_stream_id " + | |
| 53 | + "WHERE gs.app=#{app} AND gs.stream=#{stream} AND pgs.platform_id=#{serverGBId}") | |
| 54 | 54 | StreamProxyItem selectOne(String app, String stream, String serverGBId); |
| 55 | 55 | |
| 56 | 56 | @Select("select gs.* \n" + |
| 57 | - "from gb_stream gs\n" + | |
| 58 | - " left join platform_gb_stream pgs\n" + | |
| 59 | - " on gs.gbStreamId = pgs.gbStreamId\n" + | |
| 60 | - "where pgs.platformId=#{platformId} and pgs.catalogId=#{catalogId}") | |
| 57 | + "from wvp_gb_stream gs\n" + | |
| 58 | + " left join wvp_platform_gb_stream pgs\n" + | |
| 59 | + " on gs.gb_stream_id = pgs.gb_stream_id\n" + | |
| 60 | + "where pgs.platform_id=#{platformId} and pgs.catalog_id=#{catalogId}") | |
| 61 | 61 | List<GbStream> queryChannelInParentPlatformAndCatalog(String platformId, String catalogId); |
| 62 | 62 | |
| 63 | - @Select("select gs.gbId as id, gs.name as name, pgs.platformId as platformId, pgs.catalogId as catalogId , 0 as childrenCount, 2 as type\n" + | |
| 64 | - "from gb_stream gs\n" + | |
| 65 | - " left join platform_gb_stream pgs\n" + | |
| 66 | - " on gs.gbStreamId = pgs.gbStreamId\n" + | |
| 67 | - "where pgs.platformId=#{platformId} and pgs.catalogId=#{catalogId}") | |
| 63 | + @Select("select gs.gb_id as id, gs.name as name, pgs.platform_id as platform_id, pgs.catalog_id as catalog_id , 0 as children_count, 2 as type\n" + | |
| 64 | + "from wvp_gb_stream gs\n" + | |
| 65 | + " left join wvp_platform_gb_stream pgs\n" + | |
| 66 | + " on gs.gb_stream_id = pgs.gb_stream_id\n" + | |
| 67 | + "where pgs.platform_id=#{platformId} and pgs.catalog_id=#{catalogId}") | |
| 68 | 68 | List<PlatformCatalog> queryChannelInParentPlatformAndCatalogForCatalog(String platformId, String catalogId); |
| 69 | 69 | |
| 70 | - @Delete("DELETE FROM platform_gb_stream WHERE catalogId=#{id}") | |
| 70 | + @Delete("DELETE from wvp_platform_gb_stream WHERE catalog_id=#{id}") | |
| 71 | 71 | int delByCatalogId(String id); |
| 72 | 72 | |
| 73 | 73 | @Select("<script> " + |
| 74 | 74 | "SELECT " + |
| 75 | 75 | "pp.* " + |
| 76 | 76 | "FROM " + |
| 77 | - "parent_platform pp " + | |
| 78 | - "left join platform_gb_stream pgs on " + | |
| 79 | - "pp.serverGBId = pgs.platformId " + | |
| 80 | - "left join gb_stream gs " + | |
| 81 | - "on gs.gbStreamId = pgs.gbStreamId " + | |
| 77 | + "wvp_platform pp " + | |
| 78 | + "left join wvp_platform_gb_stream pgs on " + | |
| 79 | + "pp.server_gb_id = pgs.platform_id " + | |
| 80 | + "left join wvp_gb_stream gs " + | |
| 81 | + "on gs.gb_stream_id = pgs.gb_stream_id " + | |
| 82 | 82 | "WHERE " + |
| 83 | 83 | "gs.app = #{app} " + |
| 84 | 84 | "AND gs.stream = #{stream}" + |
| 85 | - "AND pp.serverGBId IN" + | |
| 85 | + "AND pp.server_gb_id IN" + | |
| 86 | 86 | "<foreach collection='platforms' item='item' open='(' separator=',' close=')' > #{item}</foreach>" + |
| 87 | 87 | "</script> ") |
| 88 | 88 | List<ParentPlatform> queryPlatFormListForGBWithGBId(String app, String stream, List<String> platforms); |
| 89 | 89 | |
| 90 | - @Delete("DELETE FROM platform_gb_stream WHERE gbStreamId = (select id from gb_stream where app=#{app} AND stream=#{stream}) AND platformId=#{platformId}") | |
| 90 | + @Delete("DELETE from wvp_platform_gb_stream WHERE gb_stream_id = (select id from wvp_gb_stream where app=#{app} AND stream=#{stream}) AND platform_id=#{platformId}") | |
| 91 | 91 | int delByAppAndStreamAndPlatform(String app, String stream, String platformId); |
| 92 | 92 | |
| 93 | 93 | @Delete("<script> "+ |
| 94 | - "DELETE FROM platform_gb_stream where gbStreamId in " + | |
| 94 | + "DELETE from wvp_platform_gb_stream where gb_stream_id in " + | |
| 95 | 95 | "<foreach collection='gbStreams' item='item' open='(' separator=',' close=')' >" + |
| 96 | 96 | "#{item.gbStreamId}" + |
| 97 | 97 | "</foreach>" + |
| ... | ... | @@ -99,13 +99,13 @@ public interface PlatformGbStreamMapper { |
| 99 | 99 | void delByGbStreams(List<GbStream> gbStreams); |
| 100 | 100 | |
| 101 | 101 | @Delete("<script> "+ |
| 102 | - "DELETE FROM platform_gb_stream where platformId=#{platformId} and gbStreamId in " + | |
| 102 | + "DELETE from wvp_platform_gb_stream where platform_id=#{platformId} and gb_stream_id in " + | |
| 103 | 103 | "<foreach collection='gbStreams' item='item' open='(' separator=',' close=')'>" + |
| 104 | 104 | "#{item.gbStreamId} " + |
| 105 | 105 | "</foreach>" + |
| 106 | 106 | "</script>") |
| 107 | 107 | void delByAppAndStreamsByPlatformId(List<GbStream> gbStreams, String platformId); |
| 108 | 108 | |
| 109 | - @Delete("DELETE FROM platform_gb_stream WHERE platformId=#{platformId} and catalogId=#{catalogId}") | |
| 109 | + @Delete("DELETE from wvp_platform_gb_stream WHERE platform_id=#{platformId} and catalog_id=#{catalogId}") | |
| 110 | 110 | int delByPlatformAndCatalogId(String platformId, String catalogId); |
| 111 | 111 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/RecordInfoDao.java deleted
100644 → 0
| 1 | -package com.genersoft.iot.vmp.storager.dao; | |
| 2 | - | |
| 3 | -import com.genersoft.iot.vmp.storager.dao.dto.RecordInfo; | |
| 4 | -import org.apache.ibatis.annotations.Delete; | |
| 5 | -import org.apache.ibatis.annotations.Insert; | |
| 6 | -import org.apache.ibatis.annotations.Mapper; | |
| 7 | -import org.apache.ibatis.annotations.Select; | |
| 8 | -import org.springframework.stereotype.Repository; | |
| 9 | - | |
| 10 | -import java.util.List; | |
| 11 | - | |
| 12 | -@Mapper | |
| 13 | -@Repository | |
| 14 | -public interface RecordInfoDao { | |
| 15 | - | |
| 16 | - @Insert("INSERT INTO recordInfo (app, stream, mediaServerId, createTime, type, deviceId, channelId, name) VALUES" + | |
| 17 | - "(#{app}, #{stream}, #{mediaServerId}, datetime('now','localtime')), #{type}, #{deviceId}, #{channelId}, #{name}") | |
| 18 | - int add(RecordInfo recordInfo); | |
| 19 | - | |
| 20 | - @Delete("DELETE FROM user WHERE createTime < #{beforeTime}") | |
| 21 | - int deleteBefore(String beforeTime); | |
| 22 | - | |
| 23 | - @Select("select * FROM recordInfo") | |
| 24 | - List<RecordInfo> selectAll(); | |
| 25 | -} |
src/main/java/com/genersoft/iot/vmp/storager/dao/RoleMapper.java
| 1 | 1 | package com.genersoft.iot.vmp.storager.dao; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.storager.dao.dto.Role; |
| 4 | -import com.genersoft.iot.vmp.storager.dao.dto.User; | |
| 5 | 4 | import org.apache.ibatis.annotations.*; |
| 6 | 5 | import org.springframework.stereotype.Repository; |
| 7 | 6 | |
| ... | ... | @@ -11,25 +10,25 @@ import java.util.List; |
| 11 | 10 | @Repository |
| 12 | 11 | public interface RoleMapper { |
| 13 | 12 | |
| 14 | - @Insert("INSERT INTO user_role (name, authority, createTime, updateTime) VALUES" + | |
| 13 | + @Insert("INSERT INTO wvp_user_role (name, authority, create_time, update_time) VALUES" + | |
| 15 | 14 | "(#{name}, #{authority}, #{createTime}, #{updateTime})") |
| 16 | 15 | int add(Role role); |
| 17 | 16 | |
| 18 | 17 | @Update(value = {" <script>" + |
| 19 | - "UPDATE user_role " + | |
| 20 | - "SET updateTime=#{updateTime} " + | |
| 18 | + "UPDATE wvp_user_role " + | |
| 19 | + "SET update_time=#{updateTime} " + | |
| 21 | 20 | "<if test=\"name != null\">, name=#{name}</if>" + |
| 22 | 21 | "<if test=\"authority != null\">, authority=#{authority}</if>" + |
| 23 | 22 | "WHERE id != 1 and id=#{id}" + |
| 24 | 23 | " </script>"}) |
| 25 | 24 | int update(Role role); |
| 26 | 25 | |
| 27 | - @Delete("DELETE FROM user_role WHERE id != 1 and id=#{id}") | |
| 26 | + @Delete("DELETE from wvp_user_role WHERE id != 1 and id=#{id}") | |
| 28 | 27 | int delete(int id); |
| 29 | 28 | |
| 30 | - @Select("select * FROM user_role WHERE id=#{id}") | |
| 29 | + @Select("select * from wvp_user_role WHERE id=#{id}") | |
| 31 | 30 | Role selectById(int id); |
| 32 | 31 | |
| 33 | - @Select("select * FROM user_role") | |
| 32 | + @Select("select * from wvp_user_role") | |
| 34 | 33 | List<Role> selectAll(); |
| 35 | 34 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
| 1 | 1 | package com.genersoft.iot.vmp.storager.dao; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; |
| 4 | -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; | |
| 4 | +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; | |
| 5 | 5 | import org.apache.ibatis.annotations.*; |
| 6 | 6 | import org.springframework.stereotype.Repository; |
| 7 | 7 | |
| ... | ... | @@ -11,72 +11,79 @@ import java.util.List; |
| 11 | 11 | @Repository |
| 12 | 12 | public interface StreamProxyMapper { |
| 13 | 13 | |
| 14 | - @Insert("INSERT INTO stream_proxy (type, name, app, stream,mediaServerId, url, src_url, dst_url, " + | |
| 15 | - "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_audio, enable_mp4, enable, status, enable_remove_none_reader, enable_disable_none_reader, createTime) VALUES" + | |
| 16 | - "(#{type}, #{name}, #{app}, #{stream}, #{mediaServerId}, #{url}, #{src_url}, #{dst_url}, " + | |
| 17 | - "#{timeout_ms}, #{ffmpeg_cmd_key}, #{rtp_type}, #{enable_audio}, #{enable_mp4}, #{enable}, #{status}, " + | |
| 18 | - "#{enable_remove_none_reader}, #{enable_disable_none_reader}, #{createTime} )") | |
| 14 | + @Insert("INSERT INTO wvp_stream_proxy (type, name, app, stream,media_server_id, url, src_url, dst_url, " + | |
| 15 | + "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_audio, enable_mp4, enable, status, enable_remove_none_reader, enable_disable_none_reader, create_time) VALUES" + | |
| 16 | + "(#{type}, #{name}, #{app}, #{stream}, #{mediaServerId}, #{url}, #{srcUrl}, #{dstUrl}, " + | |
| 17 | + "#{timeoutMs}, #{ffmpegCmdKey}, #{rtpType}, #{enableAudio}, #{enableMp4}, #{enable}, #{status}, " + | |
| 18 | + "#{enableRemoveNoneReader}, #{enableDisableNoneReader}, #{createTime} )") | |
| 19 | 19 | int add(StreamProxyItem streamProxyDto); |
| 20 | 20 | |
| 21 | - @Update("UPDATE stream_proxy " + | |
| 21 | + @Update("UPDATE wvp_stream_proxy " + | |
| 22 | 22 | "SET type=#{type}, " + |
| 23 | 23 | "name=#{name}," + |
| 24 | 24 | "app=#{app}," + |
| 25 | 25 | "stream=#{stream}," + |
| 26 | 26 | "url=#{url}, " + |
| 27 | - "mediaServerId=#{mediaServerId}, " + | |
| 28 | - "src_url=#{src_url}," + | |
| 29 | - "dst_url=#{dst_url}, " + | |
| 30 | - "timeout_ms=#{timeout_ms}, " + | |
| 31 | - "ffmpeg_cmd_key=#{ffmpeg_cmd_key}, " + | |
| 32 | - "rtp_type=#{rtp_type}, " + | |
| 33 | - "enable_audio=#{enable_audio}, " + | |
| 27 | + "media_server_id=#{mediaServerId}, " + | |
| 28 | + "src_url=#{srcUrl}," + | |
| 29 | + "dst_url=#{dstUrl}, " + | |
| 30 | + "timeout_ms=#{timeoutMs}, " + | |
| 31 | + "ffmpeg_cmd_key=#{ffmpegCmdKey}, " + | |
| 32 | + "rtp_type=#{rtpType}, " + | |
| 33 | + "enable_audio=#{enableAudio}, " + | |
| 34 | 34 | "enable=#{enable}, " + |
| 35 | 35 | "status=#{status}, " + |
| 36 | - "enable_remove_none_reader=#{enable_remove_none_reader}, " + | |
| 37 | - "enable_disable_none_reader=#{enable_disable_none_reader}, " + | |
| 38 | - "enable_mp4=#{enable_mp4} " + | |
| 36 | + "enable_remove_none_reader=#{enableRemoveNoneReader}, " + | |
| 37 | + "enable_disable_none_reader=#{enableDisableNoneReader}, " + | |
| 38 | + "enable_mp4=#{enableMp4} " + | |
| 39 | 39 | "WHERE app=#{app} AND stream=#{stream}") |
| 40 | 40 | int update(StreamProxyItem streamProxyDto); |
| 41 | 41 | |
| 42 | - @Delete("DELETE FROM stream_proxy WHERE app=#{app} AND stream=#{stream}") | |
| 42 | + @Delete("DELETE FROM wvp_stream_proxy WHERE app=#{app} AND stream=#{stream}") | |
| 43 | 43 | int del(String app, String stream); |
| 44 | 44 | |
| 45 | - @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream order by st.createTime desc") | |
| 45 | + @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream order by st.create_time desc") | |
| 46 | 46 | List<StreamProxyItem> selectAll(); |
| 47 | 47 | |
| 48 | - @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable=#{enable} order by st.createTime desc") | |
| 48 | + @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable=#{enable} order by st.create_time desc") | |
| 49 | 49 | List<StreamProxyItem> selectForEnable(boolean enable); |
| 50 | 50 | |
| 51 | - @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.app=#{app} AND st.stream=#{stream} order by st.createTime desc") | |
| 51 | + @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.app=#{app} AND st.stream=#{stream} order by st.create_time desc") | |
| 52 | 52 | StreamProxyItem selectOne(String app, String stream); |
| 53 | 53 | |
| 54 | - @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st " + | |
| 55 | - "LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream " + | |
| 56 | - "WHERE st.enable=#{enable} and st.mediaServerId = #{id} order by st.createTime desc") | |
| 54 | + @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st " + | |
| 55 | + "LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream " + | |
| 56 | + "WHERE st.enable=#{enable} and st.media_server_id= #{id} order by st.create_time desc") | |
| 57 | 57 | List<StreamProxyItem> selectForEnableInMediaServer(String id, boolean enable); |
| 58 | 58 | |
| 59 | - @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st " + | |
| 60 | - "LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream " + | |
| 61 | - "WHERE st.mediaServerId = #{id} order by st.createTime desc") | |
| 59 | + @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st " + | |
| 60 | + "LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream " + | |
| 61 | + "WHERE st.media_server_id= #{id} order by st.create_time desc") | |
| 62 | 62 | List<StreamProxyItem> selectInMediaServer(String id); |
| 63 | 63 | |
| 64 | - @Update("UPDATE stream_proxy " + | |
| 64 | + @Update("UPDATE wvp_stream_proxy " + | |
| 65 | 65 | "SET status=#{status} " + |
| 66 | - "WHERE mediaServerId=#{mediaServerId}") | |
| 66 | + "WHERE media_server_id=#{mediaServerId}") | |
| 67 | 67 | void updateStatusByMediaServerId(String mediaServerId, boolean status); |
| 68 | 68 | |
| 69 | - @Update("UPDATE stream_proxy " + | |
| 69 | + @Update("UPDATE wvp_stream_proxy " + | |
| 70 | 70 | "SET status=#{status} " + |
| 71 | 71 | "WHERE app=#{app} AND stream=#{stream}") |
| 72 | 72 | int updateStatus(String app, String stream, boolean status); |
| 73 | 73 | |
| 74 | - @Delete("DELETE FROM stream_proxy WHERE enable_remove_none_reader=true AND mediaServerId=#{mediaServerId}") | |
| 74 | + @Delete("DELETE FROM wvp_stream_proxy WHERE enable_remove_none_reader=true AND media_server_id=#{mediaServerId}") | |
| 75 | 75 | void deleteAutoRemoveItemByMediaServerId(String mediaServerId); |
| 76 | 76 | |
| 77 | - @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable_remove_none_reader=true AND st.mediaServerId=#{mediaServerId} order by st.createTime desc") | |
| 78 | - List<StreamProxyItem> selecAutoRemoveItemByMediaServerId(String mediaServerId); | |
| 77 | + @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable_remove_none_reader=true AND st.media_server_id=#{mediaServerId} order by st.create_time desc") | |
| 78 | + List<StreamProxyItem> selectAutoRemoveItemByMediaServerId(String mediaServerId); | |
| 79 | 79 | |
| 80 | - @Select("select count(1) as total, sum(status) as online from stream_proxy") | |
| 81 | - ResourceBaceInfo getOverview(); | |
| 80 | + @Select("select count(1) as total, sum(status) as online from wvp_stream_proxy") | |
| 81 | + ResourceBaseInfo getOverview(); | |
| 82 | + | |
| 83 | + @Select("select count(1) from wvp_stream_proxy") | |
| 84 | + | |
| 85 | + int getAllCount(); | |
| 86 | + | |
| 87 | + @Select("select count(1) from wvp_stream_proxy where status = true") | |
| 88 | + int getOnline(); | |
| 82 | 89 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
| ... | ... | @@ -3,54 +3,51 @@ package com.genersoft.iot.vmp.storager.dao; |
| 3 | 3 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; |
| 4 | 4 | import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; |
| 5 | 5 | import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; |
| 6 | -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; | |
| 7 | 6 | import org.apache.ibatis.annotations.*; |
| 8 | -// import org.omg.PortableInterceptor.INACTIVE; | |
| 9 | 7 | import org.springframework.stereotype.Repository; |
| 10 | 8 | |
| 11 | -import java.util.Collection; | |
| 12 | 9 | import java.util.List; |
| 13 | 10 | |
| 14 | 11 | @Mapper |
| 15 | 12 | @Repository |
| 16 | 13 | public interface StreamPushMapper { |
| 17 | 14 | |
| 18 | - @Insert("INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " + | |
| 19 | - "pushTime, aliveSecond, mediaServerId, serverId, updateTime, createTime, pushIng, self) VALUES" + | |
| 15 | + @Insert("INSERT INTO wvp_stream_push (app, stream, total_reader_count, origin_type, origin_type_str, " + | |
| 16 | + "push_time, alive_second, media_server_id, update_time, create_time, push_ing, self) VALUES" + | |
| 20 | 17 | "(#{app}, #{stream}, #{totalReaderCount}, #{originType}, #{originTypeStr}, " + |
| 21 | - "#{pushTime}, #{aliveSecond}, #{mediaServerId} , #{serverId} , #{updateTime} , #{createTime}, " + | |
| 18 | + "#{pushTime}, #{aliveSecond}, #{mediaServerId} , #{updateTime} , #{createTime}, " + | |
| 22 | 19 | "#{pushIng}, #{self} )") |
| 23 | 20 | int add(StreamPushItem streamPushItem); |
| 24 | 21 | |
| 25 | 22 | |
| 26 | 23 | @Update(value = {" <script>" + |
| 27 | - "UPDATE stream_push " + | |
| 28 | - "SET updateTime=#{updateTime}" + | |
| 29 | - "<if test=\"mediaServerId != null\">, mediaServerId=#{mediaServerId}</if>" + | |
| 30 | - "<if test=\"totalReaderCount != null\">, totalReaderCount=#{totalReaderCount}</if>" + | |
| 31 | - "<if test=\"originType != null\">, originType=#{originType}</if>" + | |
| 32 | - "<if test=\"originTypeStr != null\">, originTypeStr=#{originTypeStr}</if>" + | |
| 33 | - "<if test=\"pushTime != null\">, pushTime=#{pushTime}</if>" + | |
| 34 | - "<if test=\"aliveSecond != null\">, aliveSecond=#{aliveSecond}</if>" + | |
| 35 | - "<if test=\"pushIng != null\">, pushIng=#{pushIng}</if>" + | |
| 24 | + "UPDATE wvp_stream_push " + | |
| 25 | + "SET update_time=#{updateTime}" + | |
| 26 | + "<if test=\"mediaServerId != null\">, media_server_id=#{mediaServerId}</if>" + | |
| 27 | + "<if test=\"totalReaderCount != null\">, total_reader_count=#{totalReaderCount}</if>" + | |
| 28 | + "<if test=\"originType != null\">, origin_type=#{originType}</if>" + | |
| 29 | + "<if test=\"originTypeStr != null\">, origin_type_str=#{originTypeStr}</if>" + | |
| 30 | + "<if test=\"pushTime != null\">, push_time=#{pushTime}</if>" + | |
| 31 | + "<if test=\"aliveSecond != null\">, alive_second=#{aliveSecond}</if>" + | |
| 32 | + "<if test=\"pushIng != null\">, push_ing=#{pushIng}</if>" + | |
| 36 | 33 | "<if test=\"self != null\">, self=#{self}</if>" + |
| 37 | 34 | "WHERE app=#{app} AND stream=#{stream}"+ |
| 38 | 35 | " </script>"}) |
| 39 | 36 | int update(StreamPushItem streamPushItem); |
| 40 | 37 | |
| 41 | - @Delete("DELETE FROM stream_push WHERE app=#{app} AND stream=#{stream}") | |
| 38 | + @Delete("DELETE FROM wvp_stream_push WHERE app=#{app} AND stream=#{stream}") | |
| 42 | 39 | int del(String app, String stream); |
| 43 | 40 | |
| 44 | 41 | @Delete("<script> "+ |
| 45 | - "DELETE sp FROM stream_push sp left join gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream where " + | |
| 42 | + "DELETE sp FROM wvp_stream_push sp left join wvp_gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream where " + | |
| 46 | 43 | "<foreach collection='streamPushItems' item='item' separator='or'>" + |
| 47 | - "(sp.app=#{item.app} and sp.stream=#{item.stream} and gs.gbId is null) " + | |
| 44 | + "(sp.app=#{item.app} and sp.stream=#{item.stream} and gs.gb_id is null) " + | |
| 48 | 45 | "</foreach>" + |
| 49 | 46 | "</script>") |
| 50 | 47 | int delAllWithoutGBId(List<StreamPushItem> streamPushItems); |
| 51 | 48 | |
| 52 | 49 | @Delete("<script> "+ |
| 53 | - "DELETE FROM stream_push where " + | |
| 50 | + "DELETE FROM wvp_stream_push where " + | |
| 54 | 51 | "<foreach collection='streamPushItems' item='item' separator='or'>" + |
| 55 | 52 | "(app=#{item.app} and stream=#{item.stream}) " + |
| 56 | 53 | "</foreach>" + |
| ... | ... | @@ -58,7 +55,7 @@ public interface StreamPushMapper { |
| 58 | 55 | int delAll(List<StreamPushItem> streamPushItems); |
| 59 | 56 | |
| 60 | 57 | @Delete("<script> "+ |
| 61 | - "DELETE FROM stream_push where " + | |
| 58 | + "DELETE FROM wvp_stream_push where " + | |
| 62 | 59 | "<foreach collection='gbStreams' item='item' separator='or'>" + |
| 63 | 60 | "(app=#{item.app} and stream=#{item.stream}) " + |
| 64 | 61 | "</foreach>" + |
| ... | ... | @@ -69,30 +66,30 @@ public interface StreamPushMapper { |
| 69 | 66 | @Select(value = {" <script>" + |
| 70 | 67 | "SELECT " + |
| 71 | 68 | "st.*, " + |
| 72 | - "gs.gbId, gs.name, gs.longitude, gs.latitude, gs.gbStreamId " + | |
| 69 | + "gs.gb_id, gs.name, gs.longitude, gs.latitude, gs.gb_stream_id " + | |
| 73 | 70 | "from " + |
| 74 | - "stream_push st " + | |
| 75 | - "LEFT JOIN gb_stream gs " + | |
| 71 | + "wvp_stream_push st " + | |
| 72 | + "LEFT join wvp_gb_stream gs " + | |
| 76 | 73 | "on st.app = gs.app AND st.stream = gs.stream " + |
| 77 | 74 | "WHERE " + |
| 78 | 75 | "1=1 " + |
| 79 | - " <if test='query != null'> AND (st.app LIKE concat('%',#{query},'%') OR st.stream LIKE concat('%',#{query},'%') OR gs.gbId LIKE concat('%',#{query},'%') OR gs.name LIKE concat('%',#{query},'%'))</if> " + | |
| 80 | - " <if test='pushing == true' > AND (gs.gbId is null OR st.pushIng=1)</if>" + | |
| 81 | - " <if test='pushing == false' > AND (st.pushIng is null OR st.pushIng=0) </if>" + | |
| 82 | - " <if test='mediaServerId != null' > AND st.mediaServerId=#{mediaServerId} </if>" + | |
| 83 | - "order by st.createTime desc" + | |
| 76 | + " <if test='query != null'> AND (st.app LIKE concat('%',#{query},'%') OR st.stream LIKE concat('%',#{query},'%') OR gs.gb_id LIKE concat('%',#{query},'%') OR gs.name LIKE concat('%',#{query},'%'))</if> " + | |
| 77 | + " <if test='pushing == true' > AND (gs.gb_id is null OR st.push_ing=1)</if>" + | |
| 78 | + " <if test='pushing == false' > AND (st.push_ing is null OR st.push_ing=0) </if>" + | |
| 79 | + " <if test='mediaServerId != null' > AND st.media_server_id=#{mediaServerId} </if>" + | |
| 80 | + "order by st.create_time desc" + | |
| 84 | 81 | " </script>"}) |
| 85 | 82 | List<StreamPushItem> selectAllForList(String query, Boolean pushing, String mediaServerId); |
| 86 | 83 | |
| 87 | - @Select("SELECT st.*, gs.gbId, gs.name, gs.longitude, gs.latitude FROM stream_push st LEFT JOIN gb_stream gs on st.app = gs.app AND st.stream = gs.stream order by st.createTime desc") | |
| 84 | + @Select("SELECT st.*, gs.gb_id, gs.name, gs.longitude, gs.latitude FROM wvp_stream_push st LEFT join wvp_gb_stream gs on st.app = gs.app AND st.stream = gs.stream order by st.create_time desc") | |
| 88 | 85 | List<StreamPushItem> selectAll(); |
| 89 | 86 | |
| 90 | - @Select("SELECT st.*, gs.gbId, gs.name, gs.longitude, gs.latitude FROM stream_push st LEFT JOIN gb_stream gs on st.app = gs.app AND st.stream = gs.stream WHERE st.app=#{app} AND st.stream=#{stream}") | |
| 87 | + @Select("SELECT st.*, gs.gb_id, gs.name, gs.longitude, gs.latitude FROM wvp_stream_push st LEFT join wvp_gb_stream gs on st.app = gs.app AND st.stream = gs.stream WHERE st.app=#{app} AND st.stream=#{stream}") | |
| 91 | 88 | StreamPushItem selectOne(String app, String stream); |
| 92 | 89 | |
| 93 | 90 | @Insert("<script>" + |
| 94 | - "Insert IGNORE INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " + | |
| 95 | - "createTime, aliveSecond, mediaServerId, status, pushIng) " + | |
| 91 | + "Insert INTO wvp_stream_push (app, stream, total_reader_count, origin_type, origin_type_str, " + | |
| 92 | + "create_time, alive_second, media_server_id, status, push_ing) " + | |
| 96 | 93 | "VALUES <foreach collection='streamPushItems' item='item' index='index' separator=','>" + |
| 97 | 94 | "( #{item.app}, #{item.stream}, #{item.totalReaderCount}, #{item.originType}, " + |
| 98 | 95 | "#{item.originTypeStr},#{item.createTime}, #{item.aliveSecond}, #{item.mediaServerId}, #{item.status} ," + |
| ... | ... | @@ -102,37 +99,45 @@ public interface StreamPushMapper { |
| 102 | 99 | @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") |
| 103 | 100 | int addAll(List<StreamPushItem> streamPushItems); |
| 104 | 101 | |
| 105 | - @Delete("DELETE FROM stream_push") | |
| 102 | + @Delete("DELETE FROM wvp_stream_push") | |
| 106 | 103 | void clear(); |
| 107 | 104 | |
| 108 | - @Delete("DELETE sp FROM stream_push sp left join gb_stream gs on gs.app = sp.app and gs.stream= sp.stream WHERE sp.mediaServerId=#{mediaServerId} and gs.gbId is null ") | |
| 105 | + @Delete("delete" + | |
| 106 | + " from wvp_stream_push " + | |
| 107 | + " where id in " + | |
| 108 | + " (select temp.id from " + | |
| 109 | + " (select wgs.gb_stream_id as id " + | |
| 110 | + " from wvp_gb_stream wgs" + | |
| 111 | + " left join wvp_stream_push sp on sp.id = wgs.gb_stream_id" + | |
| 112 | + " where wgs.gb_id is null and wgs.media_server_id = #{mediaServerId}) temp)" | |
| 113 | + ) | |
| 109 | 114 | void deleteWithoutGBId(String mediaServerId); |
| 110 | 115 | |
| 111 | - @Select("SELECT * FROM stream_push WHERE mediaServerId=#{mediaServerId}") | |
| 116 | + @Select("SELECT * FROM wvp_stream_push WHERE media_server_id=#{mediaServerId}") | |
| 112 | 117 | List<StreamPushItem> selectAllByMediaServerId(String mediaServerId); |
| 113 | 118 | |
| 114 | - @Select("SELECT sp.* FROM stream_push sp left join gb_stream gs on gs.app = sp.app and gs.stream= sp.stream WHERE sp.mediaServerId=#{mediaServerId} and gs.gbId is null") | |
| 119 | + @Select("SELECT sp.* FROM wvp_stream_push sp left join wvp_gb_stream gs on gs.app = sp.app and gs.stream= sp.stream WHERE sp.media_server_id=#{mediaServerId} and gs.gb_id is null") | |
| 115 | 120 | List<StreamPushItem> selectAllByMediaServerIdWithOutGbID(String mediaServerId); |
| 116 | 121 | |
| 117 | - @Update("UPDATE stream_push " + | |
| 122 | + @Update("UPDATE wvp_stream_push " + | |
| 118 | 123 | "SET status=#{status} " + |
| 119 | 124 | "WHERE app=#{app} AND stream=#{stream}") |
| 120 | 125 | int updateStatus(String app, String stream, boolean status); |
| 121 | 126 | |
| 122 | - @Update("UPDATE stream_push " + | |
| 123 | - "SET pushIng=#{pushIng} " + | |
| 127 | + @Update("UPDATE wvp_stream_push " + | |
| 128 | + "SET push_ing=#{pushIng} " + | |
| 124 | 129 | "WHERE app=#{app} AND stream=#{stream}") |
| 125 | 130 | int updatePushStatus(String app, String stream, boolean pushIng); |
| 126 | 131 | |
| 127 | - @Update("UPDATE stream_push " + | |
| 132 | + @Update("UPDATE wvp_stream_push " + | |
| 128 | 133 | "SET status=#{status} " + |
| 129 | - "WHERE mediaServerId=#{mediaServerId}") | |
| 134 | + "WHERE media_server_id=#{mediaServerId}") | |
| 130 | 135 | void updateStatusByMediaServerId(String mediaServerId, boolean status); |
| 131 | 136 | |
| 132 | 137 | |
| 133 | 138 | @Select("<script> "+ |
| 134 | - "SELECT gs.* FROM stream_push sp left join gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream " + | |
| 135 | - "where sp.status = 1 and (gs.app, gs.stream) in (" + | |
| 139 | + "SELECT gs.* FROM wvp_stream_push sp left join wvp_gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream " + | |
| 140 | + "where sp.status = true and (gs.app, gs.stream) in (" + | |
| 136 | 141 | "<foreach collection='offlineStreams' item='item' separator=','>" + |
| 137 | 142 | "(#{item.app}, #{item.stream}) " + |
| 138 | 143 | "</foreach>" + |
| ... | ... | @@ -140,7 +145,7 @@ public interface StreamPushMapper { |
| 140 | 145 | List<GbStream> getOnlinePusherForGbInList(List<StreamPushItemFromRedis> offlineStreams); |
| 141 | 146 | |
| 142 | 147 | @Update("<script> "+ |
| 143 | - "UPDATE stream_push SET status=0 where (app, stream) in (" + | |
| 148 | + "UPDATE wvp_stream_push SET status=0 where (app, stream) in (" + | |
| 144 | 149 | "<foreach collection='offlineStreams' item='item' separator=','>" + |
| 145 | 150 | "(#{item.app}, #{item.stream}) " + |
| 146 | 151 | "</foreach>" + |
| ... | ... | @@ -148,7 +153,7 @@ public interface StreamPushMapper { |
| 148 | 153 | void offline(List<StreamPushItemFromRedis> offlineStreams); |
| 149 | 154 | |
| 150 | 155 | @Select("<script> "+ |
| 151 | - "SELECT * FROM stream_push sp left join gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream " + | |
| 156 | + "SELECT * FROM wvp_stream_push sp left join wvp_gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream " + | |
| 152 | 157 | "where sp.status = 0 and (gs.app, gs.stream) in (" + |
| 153 | 158 | "<foreach collection='onlineStreams' item='item' separator=','>" + |
| 154 | 159 | "(#{item.app}, #{item.stream}) " + |
| ... | ... | @@ -157,25 +162,36 @@ public interface StreamPushMapper { |
| 157 | 162 | List<GbStream> getOfflinePusherForGbInList(List<StreamPushItemFromRedis> onlineStreams); |
| 158 | 163 | |
| 159 | 164 | @Update("<script> "+ |
| 160 | - "UPDATE stream_push SET status=1 where (app, stream) in (" + | |
| 165 | + "UPDATE wvp_stream_push SET status=1 where (app, stream) in (" + | |
| 161 | 166 | "<foreach collection='onlineStreams' item='item' separator=','>" + |
| 162 | 167 | "(#{item.app}, #{item.stream}) " + |
| 163 | 168 | "</foreach>" + |
| 164 | 169 | ")</script>") |
| 165 | 170 | void online(List<StreamPushItemFromRedis> onlineStreams); |
| 166 | 171 | |
| 167 | - @Select("SELECT gs.* FROM stream_push sp left join gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream where sp.status = 1") | |
| 172 | + @Select("SELECT gs.* FROM wvp_stream_push sp left join wvp_gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream where sp.status = true") | |
| 168 | 173 | List<GbStream> getOnlinePusherForGb(); |
| 169 | 174 | |
| 170 | - @Update("UPDATE stream_push SET status=0") | |
| 175 | + @Update("UPDATE wvp_stream_push SET status=0") | |
| 171 | 176 | void setAllStreamOffline(); |
| 172 | 177 | |
| 173 | - @Select("SELECT CONCAT(app,stream) FROM gb_stream") | |
| 178 | + @Select("SELECT CONCAT(app,stream) from wvp_gb_stream") | |
| 174 | 179 | List<String> getAllAppAndStream(); |
| 175 | 180 | |
| 181 | + @Select("select count(1) from wvp_stream_push ") | |
| 182 | + int getAllCount(); | |
| 183 | + | |
| 176 | 184 | @Select(value = {" <script>" + |
| 177 | - " <if test='pushIngAsOnline == true'> select count(1) as total, sum(pushIng) as online from stream_push </if>" + | |
| 178 | - " <if test='pushIngAsOnline == false'> select count(1) as total, sum(status) as online from stream_push </if>" + | |
| 185 | + " <if test='pushIngAsOnline == true'> select count(1) from wvp_stream_push where push_ing = true </if>" + | |
| 186 | + " <if test='pushIngAsOnline == false'> select count(1)from wvp_stream_push where status = true </if>" + | |
| 179 | 187 | " </script>"}) |
| 180 | - ResourceBaceInfo getOverview(boolean pushIngAsOnline); | |
| 188 | + int getAllOnline(Boolean usePushingAsStatus); | |
| 189 | + | |
| 190 | + @Select("<script> " + | |
| 191 | + "select app, stream from wvp_stream_push where (app, stream) in " + | |
| 192 | + "<foreach collection='streamPushItems' item='item' separator=','>" + | |
| 193 | + "(#{item.app}, #{item.stream}) " + | |
| 194 | + "</foreach>" + | |
| 195 | + "</script>") | |
| 196 | + List<StreamPushItem> getListIn(List<StreamPushItem> streamPushItems); | |
| 181 | 197 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java
| ... | ... | @@ -10,56 +10,50 @@ import java.util.List; |
| 10 | 10 | @Repository |
| 11 | 11 | public interface UserMapper { |
| 12 | 12 | |
| 13 | - @Insert("INSERT INTO user (username, password, roleId, pushKey, createTime, updateTime) VALUES" + | |
| 13 | + @Insert("INSERT INTO wvp_user (username, password, role_id, push_key, create_time, update_time) VALUES" + | |
| 14 | 14 | "(#{username}, #{password}, #{role.id}, #{pushKey}, #{createTime}, #{updateTime})") |
| 15 | 15 | int add(User user); |
| 16 | 16 | |
| 17 | 17 | @Update(value = {" <script>" + |
| 18 | - "UPDATE user " + | |
| 19 | - "SET updateTime=#{updateTime} " + | |
| 20 | - "<if test=\"pushKey != null\">, pushKey=#{pushKey}</if>" + | |
| 21 | - "<if test=\"role != null\">, roleId=#{role.id}</if>" + | |
| 18 | + "UPDATE wvp_user " + | |
| 19 | + "SET update_time=#{updateTime} " + | |
| 20 | + "<if test=\"pushKey != null\">, push_key=#{pushKey}</if>" + | |
| 21 | + "<if test=\"role != null\">, role_id=#{role.id}</if>" + | |
| 22 | 22 | "<if test=\"password != null\">, password=#{password}</if>" + |
| 23 | 23 | "<if test=\"username != null\">, username=#{username}</if>" + |
| 24 | 24 | "WHERE id=#{id}" + |
| 25 | 25 | " </script>"}) |
| 26 | 26 | int update(User user); |
| 27 | 27 | |
| 28 | - @Delete("DELETE FROM user WHERE id != 1 and id=#{id}") | |
| 28 | + @Delete("DELETE from wvp_user WHERE id != 1 and id=#{id}") | |
| 29 | 29 | int delete(int id); |
| 30 | 30 | |
| 31 | - @Select("select u.*, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u, user_role r WHERE u.roleId=r.id and u.username=#{username} AND u.password=#{password}") | |
| 31 | + @Select("select u.*, r.id as role_id, r.name as roleName, r.authority as roleAuthority , r.create_time as role_create_time , r.update_time as role_update_time from wvp_user u, wvp_user_role r WHERE u.role_id=r.id and u.username=#{username} AND u.password=#{password}") | |
| 32 | 32 | @Results(id = "roleMap", value = { |
| 33 | - @Result(column = "roleID", property = "role.id"), | |
| 34 | - @Result(column = "roleName", property = "role.name"), | |
| 35 | - @Result(column = "roleAuthority", property = "role.authority"), | |
| 36 | - @Result(column = "roleCreateTime", property = "role.createTime"), | |
| 37 | - @Result(column = "roleUpdateTime", property = "role.updateTime") | |
| 33 | + @Result(column = "role_id", property = "role.id"), | |
| 34 | + @Result(column = "role_name", property = "role.name"), | |
| 35 | + @Result(column = "role_authority", property = "role.authority"), | |
| 36 | + @Result(column = "role_create_time", property = "role.createTime"), | |
| 37 | + @Result(column = "role_update_time", property = "role.updateTime") | |
| 38 | 38 | }) |
| 39 | 39 | User select(String username, String password); |
| 40 | 40 | |
| 41 | - @Select("select u.*, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u, user_role r WHERE u.roleId=r.id and u.id=#{id}") | |
| 41 | + @Select("select u.*, r.id as role_id, r.name as role_name, r.authority as role_authority , r.create_time as role_create_time , r.update_time as role_update_time from wvp_user u, wvp_user_role r WHERE u.role_id=r.id and u.id=#{id}") | |
| 42 | 42 | @ResultMap(value="roleMap") |
| 43 | 43 | User selectById(int id); |
| 44 | 44 | |
| 45 | - @Select("select u.*, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u, user_role r WHERE u.roleId=r.id and u.username=#{username}") | |
| 45 | + @Select("select u.*, r.id as role_id, r.name as role_name, r.authority as role_authority , r.create_time as role_create_time , r.update_time as role_update_time from wvp_user u, wvp_user_role r WHERE u.role_id=r.id and u.username=#{username}") | |
| 46 | 46 | @ResultMap(value="roleMap") |
| 47 | 47 | User getUserByUsername(String username); |
| 48 | 48 | |
| 49 | - @Select("select u.*, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u, user_role r WHERE u.roleId=r.id") | |
| 49 | + @Select("select u.*, r.id as role_id, r.name as role_name, r.authority as role_authority , r.create_time as role_create_time , r.update_time as role_update_time from wvp_user u, wvp_user_role r WHERE u.role_id=r.id") | |
| 50 | 50 | @ResultMap(value="roleMap") |
| 51 | 51 | List<User> selectAll(); |
| 52 | 52 | |
| 53 | - @Select("select * from (select user.*, concat(concat(#{callId}, '_'), pushKey) as str1 from user) as u where md5(u.str1) = #{sign}") | |
| 54 | - List<User> checkPushAuthorityByCallIdAndSign(String callId, String sign); | |
| 55 | - | |
| 56 | - @Select("select * from user where md5(pushKey) = #{sign}") | |
| 57 | - List<User> checkPushAuthorityByCallId(String sign); | |
| 58 | - | |
| 59 | - @Select("select u.id, u.username,u.pushKey,u.roleId, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u join user_role r on u.roleId=r.id") | |
| 53 | + @Select("select u.id, u.username,u.push_key,u.role_id, r.id as role_id, r.name as role_name, r.authority as role_authority , r.create_time as role_create_time , r.update_time as role_update_time from wvp_user u join wvp_user_role r on u.role_id=r.id") | |
| 60 | 54 | @ResultMap(value="roleMap") |
| 61 | 55 | List<User> getUsers(); |
| 62 | 56 | |
| 63 | - @Update("update user set pushKey=#{pushKey} where id=#{id}") | |
| 57 | + @Update("UPDATE wvp_user set push_key=#{pushKey} where id=#{id}") | |
| 64 | 58 | int changePushKey(int id, String pushKey); |
| 65 | 59 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
| ... | ... | @@ -561,7 +561,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 561 | 561 | |
| 562 | 562 | @Override |
| 563 | 563 | public boolean deviceIsOnline(String deviceId) { |
| 564 | - return getDevice(deviceId).getOnline() == 1; | |
| 564 | + return getDevice(deviceId).isOnLine(); | |
| 565 | 565 | } |
| 566 | 566 | |
| 567 | 567 | |
| ... | ... | @@ -587,15 +587,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 587 | 587 | } |
| 588 | 588 | |
| 589 | 589 | @Override |
| 590 | - public int getGbReceiveCount(String id) { | |
| 591 | - String playKey = VideoManagerConstants.PLAYER_PREFIX + "_" + userSetting.getServerId() + "_" + id + "_*"; | |
| 592 | - String playBackKey = VideoManagerConstants.PLAY_BLACK_PREFIX + "_" + userSetting.getServerId() + "_" + id + "_*"; | |
| 593 | - String downloadKey = VideoManagerConstants.DOWNLOAD_PREFIX + "_" + userSetting.getServerId() + "_" + id + "_*"; | |
| 594 | - | |
| 595 | - return RedisUtil.scan(redisTemplate, playKey).size() + RedisUtil.scan(redisTemplate, playBackKey).size() + RedisUtil.scan(redisTemplate, downloadKey).size(); | |
| 596 | - } | |
| 597 | - | |
| 598 | - @Override | |
| 599 | 590 | public int getGbSendCount(String id) { |
| 600 | 591 | String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX |
| 601 | 592 | + userSetting.getServerId() + "_*_" + id + "_*"; |
| ... | ... | @@ -605,18 +596,29 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 605 | 596 | @Override |
| 606 | 597 | public void sendDeviceOrChannelStatus(String deviceId, String channelId, boolean online) { |
| 607 | 598 | String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_DEVICE_STATUS; |
| 608 | - if (channelId == null) { | |
| 609 | - logger.info("[redis通知] 推送设备状态, {}-{}", deviceId, online); | |
| 610 | - }else { | |
| 611 | - logger.info("[redis通知] 推送通道状态, {}/{}-{}", deviceId, channelId, online); | |
| 599 | + StringBuilder msg = new StringBuilder(); | |
| 600 | + msg.append(deviceId); | |
| 601 | + if (channelId != null) { | |
| 602 | + msg.append(":").append(channelId); | |
| 612 | 603 | } |
| 604 | + msg.append(" ").append(online? "ON":"OFF"); | |
| 605 | + logger.info("[redis通知] 推送状态-> {} ", msg); | |
| 606 | + // 使用 RedisTemplate<Object, Object> 发送字符串消息会导致发送的消息多带了双引号 | |
| 607 | + stringRedisTemplate.convertAndSend(key, msg.toString()); | |
| 608 | + } | |
| 609 | + | |
| 610 | + @Override | |
| 611 | + public void sendChannelAddOrDelete(String deviceId, String channelId, boolean add) { | |
| 612 | + String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_DEVICE_STATUS; | |
| 613 | + | |
| 613 | 614 | |
| 614 | 615 | StringBuilder msg = new StringBuilder(); |
| 615 | 616 | msg.append(deviceId); |
| 616 | 617 | if (channelId != null) { |
| 617 | 618 | msg.append(":").append(channelId); |
| 618 | 619 | } |
| 619 | - msg.append(" ").append(online? "ON":"OFF"); | |
| 620 | + msg.append(" ").append(add? "ADD":"DELETE"); | |
| 621 | + logger.info("[redis通知] 推送通道-> {}", msg); | |
| 620 | 622 | // 使用 RedisTemplate<Object, Object> 发送字符串消息会导致发送的消息多带了双引号 |
| 621 | 623 | stringRedisTemplate.convertAndSend(key, msg.toString()); |
| 622 | 624 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
| ... | ... | @@ -116,49 +116,61 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 116 | 116 | TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); |
| 117 | 117 | // 数据去重 |
| 118 | 118 | List<DeviceChannel> channels = new ArrayList<>(); |
| 119 | + | |
| 120 | + List<DeviceChannel> updateChannels = new ArrayList<>(); | |
| 121 | + List<DeviceChannel> addChannels = new ArrayList<>(); | |
| 119 | 122 | StringBuilder stringBuilder = new StringBuilder(); |
| 120 | 123 | Map<String, Integer> subContMap = new HashMap<>(); |
| 121 | - if (deviceChannelList.size() > 0) { | |
| 122 | - // 数据去重 | |
| 123 | - Set<String> gbIdSet = new HashSet<>(); | |
| 124 | - for (DeviceChannel deviceChannel : deviceChannelList) { | |
| 125 | - if (!gbIdSet.contains(deviceChannel.getChannelId())) { | |
| 126 | - gbIdSet.add(deviceChannel.getChannelId()); | |
| 127 | - if (allChannelMap.containsKey(deviceChannel.getChannelId())) { | |
| 128 | - deviceChannel.setStreamId(allChannelMap.get(deviceChannel.getChannelId()).getStreamId()); | |
| 129 | - deviceChannel.setHasAudio(allChannelMap.get(deviceChannel.getChannelId()).isHasAudio()); | |
| 130 | - if (allChannelMap.get(deviceChannel.getChannelId()).getStatus() !=deviceChannel.getStatus()){ | |
| 131 | - List<String> strings = platformChannelMapper.queryParentPlatformByChannelId(deviceChannel.getChannelId()); | |
| 132 | - if (!CollectionUtils.isEmpty(strings)){ | |
| 133 | - strings.forEach(platformId->{ | |
| 134 | - eventPublisher.catalogEventPublish(platformId, deviceChannel, deviceChannel.getStatus()==1?CatalogEvent.ON:CatalogEvent.OFF); | |
| 135 | - }); | |
| 136 | - } | |
| 137 | 124 | |
| 138 | - } | |
| 139 | - } | |
| 140 | - channels.add(deviceChannel); | |
| 141 | - if (!ObjectUtils.isEmpty(deviceChannel.getParentId())) { | |
| 142 | - if (subContMap.get(deviceChannel.getParentId()) == null) { | |
| 143 | - subContMap.put(deviceChannel.getParentId(), 1); | |
| 144 | - }else { | |
| 145 | - Integer count = subContMap.get(deviceChannel.getParentId()); | |
| 146 | - subContMap.put(deviceChannel.getParentId(), count++); | |
| 147 | - } | |
| 125 | + // 数据去重 | |
| 126 | + Set<String> gbIdSet = new HashSet<>(); | |
| 127 | + for (DeviceChannel deviceChannel : deviceChannelList) { | |
| 128 | + if (gbIdSet.contains(deviceChannel.getChannelId())) { | |
| 129 | + stringBuilder.append(deviceChannel.getChannelId()).append(","); | |
| 130 | + continue; | |
| 131 | + } | |
| 132 | + gbIdSet.add(deviceChannel.getChannelId()); | |
| 133 | + if (allChannelMap.containsKey(deviceChannel.getChannelId())) { | |
| 134 | + deviceChannel.setStreamId(allChannelMap.get(deviceChannel.getChannelId()).getStreamId()); | |
| 135 | + deviceChannel.setHasAudio(allChannelMap.get(deviceChannel.getChannelId()).isHasAudio()); | |
| 136 | + if (allChannelMap.get(deviceChannel.getChannelId()).isStatus() !=deviceChannel.isStatus()){ | |
| 137 | + List<String> strings = platformChannelMapper.queryParentPlatformByChannelId(deviceChannel.getChannelId()); | |
| 138 | + if (!CollectionUtils.isEmpty(strings)){ | |
| 139 | + strings.forEach(platformId->{ | |
| 140 | + eventPublisher.catalogEventPublish(platformId, deviceChannel, deviceChannel.isStatus()?CatalogEvent.ON:CatalogEvent.OFF); | |
| 141 | + }); | |
| 148 | 142 | } |
| 143 | + | |
| 144 | + } | |
| 145 | + deviceChannel.setUpdateTime(DateUtil.getNow()); | |
| 146 | + updateChannels.add(deviceChannel); | |
| 147 | + }else { | |
| 148 | + deviceChannel.setCreateTime(DateUtil.getNow()); | |
| 149 | + deviceChannel.setUpdateTime(DateUtil.getNow()); | |
| 150 | + addChannels.add(deviceChannel); | |
| 151 | + } | |
| 152 | + channels.add(deviceChannel); | |
| 153 | + if (!ObjectUtils.isEmpty(deviceChannel.getParentId())) { | |
| 154 | + if (subContMap.get(deviceChannel.getParentId()) == null) { | |
| 155 | + subContMap.put(deviceChannel.getParentId(), 1); | |
| 149 | 156 | }else { |
| 150 | - stringBuilder.append(deviceChannel.getChannelId()).append(","); | |
| 157 | + Integer count = subContMap.get(deviceChannel.getParentId()); | |
| 158 | + subContMap.put(deviceChannel.getParentId(), count++); | |
| 151 | 159 | } |
| 152 | 160 | } |
| 153 | - if (channels.size() > 0) { | |
| 154 | - for (DeviceChannel channel : channels) { | |
| 155 | - if (subContMap.get(channel.getChannelId()) != null){ | |
| 156 | - channel.setSubCount(subContMap.get(channel.getChannelId())); | |
| 161 | + } | |
| 162 | + if (channels.size() > 0) { | |
| 163 | + for (DeviceChannel channel : channels) { | |
| 164 | + if (subContMap.get(channel.getChannelId()) != null){ | |
| 165 | + Integer count = subContMap.get(channel.getChannelId()); | |
| 166 | + if (count > 0) { | |
| 167 | + channel.setSubCount(count); | |
| 168 | + channel.setParental(1); | |
| 157 | 169 | } |
| 158 | 170 | } |
| 159 | 171 | } |
| 160 | - | |
| 161 | 172 | } |
| 173 | + | |
| 162 | 174 | if (stringBuilder.length() > 0) { |
| 163 | 175 | logger.info("[目录查询]收到的数据存在重复: {}" , stringBuilder); |
| 164 | 176 | } |
| ... | ... | @@ -168,21 +180,36 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 168 | 180 | } |
| 169 | 181 | try { |
| 170 | 182 | int cleanChannelsResult = deviceChannelMapper.cleanChannelsNotInList(deviceId, channels); |
| 183 | + | |
| 171 | 184 | int limitCount = 300; |
| 172 | 185 | boolean result = cleanChannelsResult < 0; |
| 173 | - if (!result && channels.size() > 0) { | |
| 174 | - if (channels.size() > limitCount) { | |
| 175 | - for (int i = 0; i < channels.size(); i += limitCount) { | |
| 186 | + if (!result && addChannels.size() > 0) { | |
| 187 | + if (addChannels.size() > limitCount) { | |
| 188 | + for (int i = 0; i < addChannels.size(); i += limitCount) { | |
| 189 | + int toIndex = i + limitCount; | |
| 190 | + if (i + limitCount > addChannels.size()) { | |
| 191 | + toIndex = addChannels.size(); | |
| 192 | + } | |
| 193 | + result = result || deviceChannelMapper.batchAdd(addChannels.subList(i, toIndex)) < 0; | |
| 194 | + } | |
| 195 | + }else { | |
| 196 | + result = result || deviceChannelMapper.batchAdd(addChannels) < 0; | |
| 197 | + } | |
| 198 | + } | |
| 199 | + if (!result && updateChannels.size() > 0) { | |
| 200 | + if (updateChannels.size() > limitCount) { | |
| 201 | + for (int i = 0; i < updateChannels.size(); i += limitCount) { | |
| 176 | 202 | int toIndex = i + limitCount; |
| 177 | - if (i + limitCount > channels.size()) { | |
| 178 | - toIndex = channels.size(); | |
| 203 | + if (i + limitCount > updateChannels.size()) { | |
| 204 | + toIndex = updateChannels.size(); | |
| 179 | 205 | } |
| 180 | - result = result || deviceChannelMapper.batchAddOrUpdate(channels.subList(i, toIndex)) < 0; | |
| 206 | + result = result || deviceChannelMapper.batchUpdate(updateChannels.subList(i, toIndex)) < 0; | |
| 181 | 207 | } |
| 182 | 208 | }else { |
| 183 | - result = result || deviceChannelMapper.batchAddOrUpdate(channels) < 0; | |
| 209 | + result = result || deviceChannelMapper.batchUpdate(updateChannels) < 0; | |
| 184 | 210 | } |
| 185 | 211 | } |
| 212 | + | |
| 186 | 213 | if (result) { |
| 187 | 214 | //事务回滚 |
| 188 | 215 | dataSourceTransactionManager.rollback(transactionStatus); |
| ... | ... | @@ -766,25 +793,49 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 766 | 793 | if (platform == null) { |
| 767 | 794 | return 0; |
| 768 | 795 | } |
| 769 | - if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)) { | |
| 770 | - if (platform.getDeviceGBId().equals(platformCatalog.getParentId())) { | |
| 771 | - // 第一层节点 | |
| 772 | - platformCatalog.setBusinessGroupId(platformCatalog.getId()); | |
| 773 | - platformCatalog.setParentId(platform.getDeviceGBId()); | |
| 774 | - }else { | |
| 775 | - // 获取顶层的 | |
| 776 | - PlatformCatalog topCatalog = getTopCatalog(platformCatalog.getParentId(), platform.getDeviceGBId()); | |
| 777 | - platformCatalog.setBusinessGroupId(topCatalog.getId()); | |
| 796 | + if (platformCatalog.getId().length() <= 8) { | |
| 797 | + platformCatalog.setCivilCode(platformCatalog.getParentId()); | |
| 798 | + }else { | |
| 799 | + if (platformCatalog.getId().length() != 20) { | |
| 800 | + return 0; | |
| 778 | 801 | } |
| 779 | - } | |
| 780 | - if (platform.getTreeType().equals(TreeType.CIVIL_CODE)) { | |
| 781 | - platformCatalog.setCivilCode(platformCatalog.getId()); | |
| 782 | - if (platformCatalog.getPlatformId().equals(platformCatalog.getParentId())) { | |
| 783 | - // 第一层节点 | |
| 784 | - platformCatalog.setParentId(platform.getDeviceGBId()); | |
| 802 | + if (platformCatalog.getParentId() != null) { | |
| 803 | + switch (Integer.parseInt(platformCatalog.getId().substring(10, 13))){ | |
| 804 | + case 200: | |
| 805 | + case 215: | |
| 806 | + if (platformCatalog.getParentId().length() <= 8) { | |
| 807 | + platformCatalog.setCivilCode(platformCatalog.getParentId()); | |
| 808 | + }else { | |
| 809 | + PlatformCatalog catalog = catalogMapper.select(platformCatalog.getParentId()); | |
| 810 | + if (catalog != null) { | |
| 811 | + platformCatalog.setCivilCode(catalog.getCivilCode()); | |
| 812 | + } | |
| 813 | + } | |
| 814 | + break; | |
| 815 | + case 216: | |
| 816 | + if (platformCatalog.getParentId().length() <= 8) { | |
| 817 | + platformCatalog.setCivilCode(platformCatalog.getParentId()); | |
| 818 | + }else { | |
| 819 | + PlatformCatalog catalog = catalogMapper.select(platformCatalog.getParentId()); | |
| 820 | + if (catalog == null) { | |
| 821 | + logger.warn("[添加目录] 无法获取目录{}的CivilCode和BusinessGroupId", platformCatalog.getPlatformId()); | |
| 822 | + break; | |
| 823 | + } | |
| 824 | + platformCatalog.setCivilCode(catalog.getCivilCode()); | |
| 825 | + if (Integer.parseInt(platformCatalog.getParentId().substring(10, 13)) == 215) { | |
| 826 | + platformCatalog.setBusinessGroupId(platformCatalog.getParentId()); | |
| 827 | + }else { | |
| 828 | + if (Integer.parseInt(platformCatalog.getParentId().substring(10, 13)) == 216) { | |
| 829 | + platformCatalog.setBusinessGroupId(catalog.getBusinessGroupId()); | |
| 830 | + } | |
| 831 | + } | |
| 832 | + } | |
| 833 | + break; | |
| 834 | + default: | |
| 835 | + break; | |
| 836 | + } | |
| 785 | 837 | } |
| 786 | 838 | } |
| 787 | - | |
| 788 | 839 | int result = catalogMapper.add(platformCatalog); |
| 789 | 840 | if (result > 0) { |
| 790 | 841 | DeviceChannel deviceChannel = getDeviceChannelByCatalog(platformCatalog); |
| ... | ... | @@ -908,19 +959,14 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 908 | 959 | DeviceChannel deviceChannel = new DeviceChannel(); |
| 909 | 960 | deviceChannel.setChannelId(catalog.getId()); |
| 910 | 961 | deviceChannel.setName(catalog.getName()); |
| 911 | - deviceChannel.setLongitude(0.0); | |
| 912 | - deviceChannel.setLatitude(0.0); | |
| 913 | 962 | deviceChannel.setDeviceId(platform.getDeviceGBId()); |
| 914 | 963 | deviceChannel.setManufacture("wvp-pro"); |
| 915 | - deviceChannel.setStatus(1); | |
| 964 | + deviceChannel.setStatus(true); | |
| 916 | 965 | deviceChannel.setParental(1); |
| 917 | 966 | |
| 918 | 967 | deviceChannel.setRegisterWay(1); |
| 919 | - // 行政区划应该是Domain的前八位 | |
| 920 | - if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)) { | |
| 921 | - deviceChannel.setParentId(catalog.getParentId()); | |
| 922 | - deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId()); | |
| 923 | - } | |
| 968 | + deviceChannel.setParentId(catalog.getParentId()); | |
| 969 | + deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId()); | |
| 924 | 970 | |
| 925 | 971 | deviceChannel.setModel("live"); |
| 926 | 972 | deviceChannel.setOwner("wvp-pro"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java
| ... | ... | @@ -32,11 +32,17 @@ public class DateUtil { |
| 32 | 32 | */ |
| 33 | 33 | public static final String PATTERN = "yyyy-MM-dd HH:mm:ss"; |
| 34 | 34 | |
| 35 | + /** | |
| 36 | + * wvp内部统一时间格式 | |
| 37 | + */ | |
| 38 | + public static final String URL_PATTERN = "yyyyMMddHHmmss"; | |
| 39 | + | |
| 35 | 40 | public static final String zoneStr = "Asia/Shanghai"; |
| 36 | 41 | |
| 37 | 42 | public static final DateTimeFormatter formatterCompatibleISO8601 = DateTimeFormatter.ofPattern(ISO8601_COMPATIBLE_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); |
| 38 | 43 | public static final DateTimeFormatter formatterISO8601 = DateTimeFormatter.ofPattern(ISO8601_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); |
| 39 | 44 | public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); |
| 45 | + public static final DateTimeFormatter urlFormatter = DateTimeFormatter.ofPattern(URL_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); | |
| 40 | 46 | |
| 41 | 47 | public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) { |
| 42 | 48 | |
| ... | ... | @@ -68,6 +74,15 @@ public class DateUtil { |
| 68 | 74 | } |
| 69 | 75 | |
| 70 | 76 | /** |
| 77 | + * 获取当前时间 | |
| 78 | + * @return | |
| 79 | + */ | |
| 80 | + public static String getNowForUrl() { | |
| 81 | + LocalDateTime nowDateTime = LocalDateTime.now(); | |
| 82 | + return urlFormatter.format(nowDateTime); | |
| 83 | + } | |
| 84 | + | |
| 85 | + /** | |
| 71 | 86 | * 格式校验 |
| 72 | 87 | * @param timeStr 时间字符串 |
| 73 | 88 | * @param dateTimeFormatter 待校验的格式 | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java
| ... | ... | @@ -6,7 +6,7 @@ package com.genersoft.iot.vmp.vmanager.bean; |
| 6 | 6 | public enum ErrorCode { |
| 7 | 7 | SUCCESS(0, "成功"), |
| 8 | 8 | ERROR100(100, "失败"), |
| 9 | - ERROR400(400, "参数不全或者错误"), | |
| 9 | + ERROR400(400, "参数或方法错误"), | |
| 10 | 10 | ERROR404(404, "资源未找到"), |
| 11 | 11 | ERROR403(403, "无权限操作"), |
| 12 | 12 | ERROR401(401, "请登录后重新请求"), | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceBaceInfo.java renamed to src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceBaseInfo.java
| 1 | 1 | package com.genersoft.iot.vmp.vmanager.bean; |
| 2 | 2 | |
| 3 | -public class ResourceBaceInfo { | |
| 3 | +public class ResourceBaseInfo { | |
| 4 | 4 | private int total; |
| 5 | 5 | private int online; |
| 6 | 6 | |
| 7 | + public ResourceBaseInfo() { | |
| 8 | + } | |
| 9 | + | |
| 10 | + public ResourceBaseInfo(int total, int online) { | |
| 11 | + this.total = total; | |
| 12 | + this.online = online; | |
| 13 | + } | |
| 14 | + | |
| 7 | 15 | public int getTotal() { |
| 8 | 16 | return total; |
| 9 | 17 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceInfo.java
| ... | ... | @@ -2,40 +2,40 @@ package com.genersoft.iot.vmp.vmanager.bean; |
| 2 | 2 | |
| 3 | 3 | public class ResourceInfo { |
| 4 | 4 | |
| 5 | - private ResourceBaceInfo device; | |
| 6 | - private ResourceBaceInfo channel; | |
| 7 | - private ResourceBaceInfo push; | |
| 8 | - private ResourceBaceInfo proxy; | |
| 5 | + private ResourceBaseInfo device; | |
| 6 | + private ResourceBaseInfo channel; | |
| 7 | + private ResourceBaseInfo push; | |
| 8 | + private ResourceBaseInfo proxy; | |
| 9 | 9 | |
| 10 | - public ResourceBaceInfo getDevice() { | |
| 10 | + public ResourceBaseInfo getDevice() { | |
| 11 | 11 | return device; |
| 12 | 12 | } |
| 13 | 13 | |
| 14 | - public void setDevice(ResourceBaceInfo device) { | |
| 14 | + public void setDevice(ResourceBaseInfo device) { | |
| 15 | 15 | this.device = device; |
| 16 | 16 | } |
| 17 | 17 | |
| 18 | - public ResourceBaceInfo getChannel() { | |
| 18 | + public ResourceBaseInfo getChannel() { | |
| 19 | 19 | return channel; |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | - public void setChannel(ResourceBaceInfo channel) { | |
| 22 | + public void setChannel(ResourceBaseInfo channel) { | |
| 23 | 23 | this.channel = channel; |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | - public ResourceBaceInfo getPush() { | |
| 26 | + public ResourceBaseInfo getPush() { | |
| 27 | 27 | return push; |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | - public void setPush(ResourceBaceInfo push) { | |
| 30 | + public void setPush(ResourceBaseInfo push) { | |
| 31 | 31 | this.push = push; |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | - public ResourceBaceInfo getProxy() { | |
| 34 | + public ResourceBaseInfo getProxy() { | |
| 35 | 35 | return proxy; |
| 36 | 36 | } |
| 37 | 37 | |
| 38 | - public void setProxy(ResourceBaceInfo proxy) { | |
| 38 | + public void setProxy(ResourceBaseInfo proxy) { | |
| 39 | 39 | this.proxy = proxy; |
| 40 | 40 | } |
| 41 | 41 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/bean/SnapPath.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.vmanager.bean; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | + | |
| 5 | +@Schema(description = "截图地址信息") | |
| 6 | +public class SnapPath { | |
| 7 | + | |
| 8 | + @Schema(description = "相对地址") | |
| 9 | + private String path; | |
| 10 | + | |
| 11 | + @Schema(description = "绝对地址") | |
| 12 | + private String absoluteFilePath; | |
| 13 | + | |
| 14 | + @Schema(description = "请求地址") | |
| 15 | + private String url; | |
| 16 | + | |
| 17 | + | |
| 18 | + public static SnapPath getInstance(String path, String absoluteFilePath, String url) { | |
| 19 | + SnapPath snapPath = new SnapPath(); | |
| 20 | + snapPath.setPath(path); | |
| 21 | + snapPath.setAbsoluteFilePath(absoluteFilePath); | |
| 22 | + snapPath.setUrl(url); | |
| 23 | + return snapPath; | |
| 24 | + } | |
| 25 | + | |
| 26 | + | |
| 27 | + public String getPath() { | |
| 28 | + return path; | |
| 29 | + } | |
| 30 | + | |
| 31 | + public void setPath(String path) { | |
| 32 | + this.path = path; | |
| 33 | + } | |
| 34 | + | |
| 35 | + public String getAbsoluteFilePath() { | |
| 36 | + return absoluteFilePath; | |
| 37 | + } | |
| 38 | + | |
| 39 | + public void setAbsoluteFilePath(String absoluteFilePath) { | |
| 40 | + this.absoluteFilePath = absoluteFilePath; | |
| 41 | + } | |
| 42 | + | |
| 43 | + public String getUrl() { | |
| 44 | + return url; | |
| 45 | + } | |
| 46 | + | |
| 47 | + public void setUrl(String url) { | |
| 48 | + this.url = url; | |
| 49 | + } | |
| 50 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java
| ... | ... | @@ -102,7 +102,7 @@ public class MobilePositionController { |
| 102 | 102 | public DeferredResult<MobilePosition> realTimePosition(@PathVariable String deviceId) { |
| 103 | 103 | Device device = storager.queryVideoDevice(deviceId); |
| 104 | 104 | String uuid = UUID.randomUUID().toString(); |
| 105 | - String key = DeferredResultHolder.CALLBACK_CMD_MOBILEPOSITION + deviceId; | |
| 105 | + String key = DeferredResultHolder.CALLBACK_CMD_MOBILE_POSITION + deviceId; | |
| 106 | 106 | try { |
| 107 | 107 | cmder.mobilePostitionQuery(device, event -> { |
| 108 | 108 | RequestMessage msg = new RequestMessage(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
| ... | ... | @@ -466,10 +466,12 @@ public class DeviceQuery { |
| 466 | 466 | @Operation(summary = "请求截图") |
| 467 | 467 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 468 | 468 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 469 | - public void getSnap(HttpServletResponse resp, @PathVariable String deviceId, @PathVariable String channelId) { | |
| 469 | + @Parameter(name = "mark", description = "标识", required = false) | |
| 470 | + public void getSnap(HttpServletResponse resp, @PathVariable String deviceId, @PathVariable String channelId, @RequestParam(required = false) String mark) { | |
| 470 | 471 | |
| 471 | 472 | try { |
| 472 | - final InputStream in = Files.newInputStream(new File("snap" + File.separator + deviceId + "_" + channelId + ".jpg").toPath()); | |
| 473 | + | |
| 474 | + final InputStream in = Files.newInputStream(new File("snap" + File.separator + deviceId + "_" + channelId + (mark == null? ".jpg": ("_" + mark + ".jpg"))).toPath()); | |
| 473 | 475 | resp.setContentType(MediaType.IMAGE_PNG_VALUE); |
| 474 | 476 | IOUtils.copy(in, resp.getOutputStream()); |
| 475 | 477 | } catch (IOException e) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
| ... | ... | @@ -403,8 +403,12 @@ public class PlatformController { |
| 403 | 403 | if (platform == null) { |
| 404 | 404 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "平台未找到"); |
| 405 | 405 | } |
| 406 | - if (platformId.equals(parentId)) { | |
| 407 | - parentId = platform.getDeviceGBId(); | |
| 406 | +// if (platformId.equals(parentId)) { | |
| 407 | +// parentId = platform.getDeviceGBId(); | |
| 408 | +// } | |
| 409 | + | |
| 410 | + if (platformId.equals(platform.getDeviceGBId())) { | |
| 411 | + parentId = null; | |
| 408 | 412 | } |
| 409 | 413 | |
| 410 | 414 | return storager.getChildrenCatalogByPlatform(platformId, parentId); | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
| ... | ... | @@ -24,6 +24,7 @@ import com.genersoft.iot.vmp.service.IPlayService; |
| 24 | 24 | import com.genersoft.iot.vmp.service.bean.InviteErrorCode; |
| 25 | 25 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 26 | 26 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 27 | +import com.genersoft.iot.vmp.utils.DateUtil; | |
| 27 | 28 | import com.genersoft.iot.vmp.vmanager.bean.*; |
| 28 | 29 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 29 | 30 | import com.genersoft.iot.vmp.vmanager.bean.StreamContent; |
| ... | ... | @@ -129,7 +130,7 @@ public class PlayController { |
| 129 | 130 | if (data != null) { |
| 130 | 131 | StreamInfo streamInfo = (StreamInfo)data; |
| 131 | 132 | if (userSetting.getUseSourceIpAsStreamIp()) { |
| 132 | - streamInfo.channgeStreamIp(request.getLocalName()); | |
| 133 | + streamInfo.channgeStreamIp(request.getLocalAddr()); | |
| 133 | 134 | } |
| 134 | 135 | wvpResult.setData(new StreamContent(streamInfo)); |
| 135 | 136 | } |
| ... | ... | @@ -146,8 +147,9 @@ public class PlayController { |
| 146 | 147 | @Operation(summary = "停止点播") |
| 147 | 148 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 148 | 149 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 150 | + @Parameter(name = "isSubStream", description = "是否子码流(true-子码流,false-主码流),默认为false", required = true) | |
| 149 | 151 | @GetMapping("/stop/{deviceId}/{channelId}") |
| 150 | - public JSONObject playStop(@PathVariable String deviceId, @PathVariable String channelId) { | |
| 152 | + public JSONObject playStop(@PathVariable String deviceId, @PathVariable String channelId,boolean isSubStream) { | |
| 151 | 153 | |
| 152 | 154 | logger.debug(String.format("设备预览/回放停止API调用,streamId:%s_%s", deviceId, channelId )); |
| 153 | 155 | |
| ... | ... | @@ -174,11 +176,12 @@ public class PlayController { |
| 174 | 176 | } |
| 175 | 177 | } |
| 176 | 178 | inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId); |
| 177 | - | |
| 178 | 179 | storager.stopPlay(deviceId, channelId); |
| 180 | + | |
| 179 | 181 | JSONObject json = new JSONObject(); |
| 180 | 182 | json.put("deviceId", deviceId); |
| 181 | 183 | json.put("channelId", channelId); |
| 184 | + json.put("isSubStream", isSubStream); | |
| 182 | 185 | return json; |
| 183 | 186 | } |
| 184 | 187 | |
| ... | ... | @@ -316,5 +319,36 @@ public class PlayController { |
| 316 | 319 | return jsonObject; |
| 317 | 320 | } |
| 318 | 321 | |
| 322 | + @Operation(summary = "获取截图") | |
| 323 | + @Parameter(name = "deviceId", description = "设备国标编号", required = true) | |
| 324 | + @Parameter(name = "channelId", description = "通道国标编号", required = true) | |
| 325 | + @Parameter(name = "isSubStream", description = "是否子码流(true-子码流,false-主码流),默认为false", required = true) | |
| 326 | + @GetMapping("/snap") | |
| 327 | + public DeferredResult<String> getSnap(String deviceId, String channelId,boolean isSubStream) { | |
| 328 | + if (logger.isDebugEnabled()) { | |
| 329 | + logger.debug("获取截图: {}/{}", deviceId, channelId); | |
| 330 | + } | |
| 331 | + | |
| 332 | + DeferredResult<String> result = new DeferredResult<>(3 * 1000L); | |
| 333 | + String key = DeferredResultHolder.CALLBACK_CMD_SNAP + deviceId; | |
| 334 | + String uuid = UUID.randomUUID().toString(); | |
| 335 | + resultHolder.put(key, uuid, result); | |
| 336 | + | |
| 337 | + RequestMessage message = new RequestMessage(); | |
| 338 | + message.setKey(key); | |
| 339 | + message.setId(uuid); | |
| 340 | + | |
| 341 | + String fileName = deviceId + "_" + channelId + "_" + DateUtil.getNowForUrl() + "jpg"; | |
| 342 | + playService.getSnap(deviceId, channelId, fileName, (code, msg, data) -> { | |
| 343 | + if (code == InviteErrorCode.SUCCESS.getCode()) { | |
| 344 | + message.setData(data); | |
| 345 | + }else { | |
| 346 | + message.setData(WVPResult.fail(code, msg)); | |
| 347 | + } | |
| 348 | + resultHolder.invokeResult(message); | |
| 349 | + }); | |
| 350 | + return result; | |
| 351 | + } | |
| 352 | + | |
| 319 | 353 | } |
| 320 | 354 | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
| ... | ... | @@ -107,7 +107,7 @@ public class PlaybackController { |
| 107 | 107 | if (data != null) { |
| 108 | 108 | StreamInfo streamInfo = (StreamInfo)data; |
| 109 | 109 | if (userSetting.getUseSourceIpAsStreamIp()) { |
| 110 | - streamInfo.channgeStreamIp(request.getLocalName()); | |
| 110 | + streamInfo.channgeStreamIp(request.getLocalAddr()); | |
| 111 | 111 | } |
| 112 | 112 | wvpResult.setData(new StreamContent(streamInfo)); |
| 113 | 113 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
| ... | ... | @@ -149,7 +149,7 @@ public class GBRecordController { |
| 149 | 149 | if (data != null) { |
| 150 | 150 | StreamInfo streamInfo = (StreamInfo)data; |
| 151 | 151 | if (userSetting.getUseSourceIpAsStreamIp()) { |
| 152 | - streamInfo.channgeStreamIp(request.getLocalName()); | |
| 152 | + streamInfo.channgeStreamIp(request.getLocalAddr()); | |
| 153 | 153 | } |
| 154 | 154 | wvpResult.setData(new StreamContent(streamInfo)); |
| 155 | 155 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
| ... | ... | @@ -15,7 +15,7 @@ import com.genersoft.iot.vmp.service.*; |
| 15 | 15 | import com.genersoft.iot.vmp.service.bean.MediaServerLoad; |
| 16 | 16 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 17 | 17 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 18 | -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; | |
| 18 | +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; | |
| 19 | 19 | import com.genersoft.iot.vmp.vmanager.bean.ResourceInfo; |
| 20 | 20 | import com.genersoft.iot.vmp.vmanager.bean.SystemConfigInfo; |
| 21 | 21 | import io.swagger.v3.oas.annotations.Operation; |
| ... | ... | @@ -251,13 +251,13 @@ public class ServerController { |
| 251 | 251 | @Operation(summary = "获取负载信息") |
| 252 | 252 | public ResourceInfo getResourceInfo() { |
| 253 | 253 | ResourceInfo result = new ResourceInfo(); |
| 254 | - ResourceBaceInfo deviceInfo = deviceService.getOverview(); | |
| 254 | + ResourceBaseInfo deviceInfo = deviceService.getOverview(); | |
| 255 | 255 | result.setDevice(deviceInfo); |
| 256 | - ResourceBaceInfo channelInfo = channelService.getOverview(); | |
| 256 | + ResourceBaseInfo channelInfo = channelService.getOverview(); | |
| 257 | 257 | result.setChannel(channelInfo); |
| 258 | - ResourceBaceInfo pushInfo = pushService.getOverview(); | |
| 258 | + ResourceBaseInfo pushInfo = pushService.getOverview(); | |
| 259 | 259 | result.setPush(pushInfo); |
| 260 | - ResourceBaceInfo proxyInfo = proxyService.getOverview(); | |
| 260 | + ResourceBaseInfo proxyInfo = proxyService.getOverview(); | |
| 261 | 261 | result.setProxy(proxyInfo); |
| 262 | 262 | |
| 263 | 263 | return result; | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
| 1 | 1 | package com.genersoft.iot.vmp.vmanager.streamProxy; |
| 2 | 2 | |
| 3 | 3 | import com.alibaba.fastjson2.JSONObject; |
| 4 | +import com.genersoft.iot.vmp.common.StreamInfo; | |
| 5 | +import com.genersoft.iot.vmp.conf.UserSetting; | |
| 4 | 6 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 7 | +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | |
| 8 | +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; | |
| 5 | 9 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 6 | 10 | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; |
| 7 | 11 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 8 | 12 | import com.genersoft.iot.vmp.service.IStreamProxyService; |
| 9 | 13 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 10 | 14 | import com.genersoft.iot.vmp.vmanager.bean.StreamContent; |
| 15 | +import com.genersoft.iot.vmp.vmanager.bean.WVPResult; | |
| 11 | 16 | import com.github.pagehelper.PageInfo; |
| 12 | 17 | import io.swagger.v3.oas.annotations.Operation; |
| 13 | 18 | import io.swagger.v3.oas.annotations.Parameter; |
| ... | ... | @@ -18,6 +23,9 @@ import org.springframework.beans.factory.annotation.Autowired; |
| 18 | 23 | import org.springframework.stereotype.Controller; |
| 19 | 24 | import org.springframework.util.ObjectUtils; |
| 20 | 25 | import org.springframework.web.bind.annotation.*; |
| 26 | +import org.springframework.web.context.request.async.DeferredResult; | |
| 27 | + | |
| 28 | +import java.util.UUID; | |
| 21 | 29 | |
| 22 | 30 | @SuppressWarnings("rawtypes") |
| 23 | 31 | /** |
| ... | ... | @@ -37,6 +45,12 @@ public class StreamProxyController { |
| 37 | 45 | @Autowired |
| 38 | 46 | private IStreamProxyService streamProxyService; |
| 39 | 47 | |
| 48 | + @Autowired | |
| 49 | + private DeferredResultHolder resultHolder; | |
| 50 | + | |
| 51 | + @Autowired | |
| 52 | + private UserSetting userSetting; | |
| 53 | + | |
| 40 | 54 | |
| 41 | 55 | @Operation(summary = "分页查询流代理") |
| 42 | 56 | @Parameter(name = "page", description = "当前页") |
| ... | ... | @@ -58,7 +72,7 @@ public class StreamProxyController { |
| 58 | 72 | }) |
| 59 | 73 | @PostMapping(value = "/save") |
| 60 | 74 | @ResponseBody |
| 61 | - public StreamContent save(@RequestBody StreamProxyItem param){ | |
| 75 | + public DeferredResult<Object> save(@RequestBody StreamProxyItem param){ | |
| 62 | 76 | logger.info("添加代理: " + JSONObject.toJSONString(param)); |
| 63 | 77 | if (ObjectUtils.isEmpty(param.getMediaServerId())) { |
| 64 | 78 | param.setMediaServerId("auto"); |
| ... | ... | @@ -69,7 +83,33 @@ public class StreamProxyController { |
| 69 | 83 | if (ObjectUtils.isEmpty(param.getGbId())) { |
| 70 | 84 | param.setGbId(null); |
| 71 | 85 | } |
| 72 | - return new StreamContent(streamProxyService.save(param)); | |
| 86 | + | |
| 87 | + RequestMessage requestMessage = new RequestMessage(); | |
| 88 | + String key = DeferredResultHolder.CALLBACK_CMD_PROXY + param.getApp() + param.getStream(); | |
| 89 | + requestMessage.setKey(key); | |
| 90 | + String uuid = UUID.randomUUID().toString(); | |
| 91 | + requestMessage.setId(uuid); | |
| 92 | + DeferredResult<Object> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); | |
| 93 | + // 录像查询以channelId作为deviceId查询 | |
| 94 | + resultHolder.put(key, uuid, result); | |
| 95 | + result.onTimeout(()->{ | |
| 96 | + WVPResult<StreamInfo> wvpResult = new WVPResult<>(); | |
| 97 | + wvpResult.setCode(ErrorCode.ERROR100.getCode()); | |
| 98 | + wvpResult.setMsg("超时"); | |
| 99 | + requestMessage.setData(wvpResult); | |
| 100 | + resultHolder.invokeAllResult(requestMessage); | |
| 101 | + }); | |
| 102 | + | |
| 103 | + streamProxyService.save(param, (code, msg, streamInfo) -> { | |
| 104 | + logger.info("[拉流代理] {}", code == ErrorCode.SUCCESS.getCode()? "成功":"失败: " + msg); | |
| 105 | + if (code == ErrorCode.SUCCESS.getCode()) { | |
| 106 | + requestMessage.setData(new StreamContent(streamInfo)); | |
| 107 | + }else { | |
| 108 | + requestMessage.setData(WVPResult.fail(code, msg)); | |
| 109 | + } | |
| 110 | + resultHolder.invokeAllResult(requestMessage); | |
| 111 | + }); | |
| 112 | + return result; | |
| 73 | 113 | } |
| 74 | 114 | |
| 75 | 115 | @GetMapping(value = "/ffmpeg_cmd/list") | ... | ... |
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiDeviceController.java
| ... | ... | @@ -89,7 +89,7 @@ public class ApiDeviceController { |
| 89 | 89 | deviceJsonObject.put("RecvStreamIP", ""); |
| 90 | 90 | deviceJsonObject.put("CatalogInterval", 3600); // 通道目录抓取周期 |
| 91 | 91 | deviceJsonObject.put("SubscribeInterval", device.getSubscribeCycleForCatalog()); // 订阅周期(秒), 0 表示后台不周期订阅 |
| 92 | - deviceJsonObject.put("Online", device.getOnline() == 1); | |
| 92 | + deviceJsonObject.put("Online", device.isOnLine()); | |
| 93 | 93 | deviceJsonObject.put("Password", ""); |
| 94 | 94 | deviceJsonObject.put("MediaTransport", device.getTransport()); |
| 95 | 95 | deviceJsonObject.put("RemoteIP", device.getIp()); |
| ... | ... | @@ -147,7 +147,7 @@ public class ApiDeviceController { |
| 147 | 147 | deviceJOSNChannel.put("ID", deviceChannelExtend.getChannelId()); |
| 148 | 148 | deviceJOSNChannel.put("DeviceID", deviceChannelExtend.getDeviceId()); |
| 149 | 149 | deviceJOSNChannel.put("DeviceName", deviceChannelExtend.getDeviceName()); |
| 150 | - deviceJOSNChannel.put("DeviceOnline", deviceChannelExtend.getDeviceOnline() == 1); | |
| 150 | + deviceJOSNChannel.put("DeviceOnline", deviceChannelExtend.isDeviceOnline()); | |
| 151 | 151 | deviceJOSNChannel.put("Channel", 0); // TODO 自定义序号 |
| 152 | 152 | deviceJOSNChannel.put("Name", deviceChannelExtend.getName()); |
| 153 | 153 | deviceJOSNChannel.put("Custom", false); |
| ... | ... | @@ -166,7 +166,7 @@ public class ApiDeviceController { |
| 166 | 166 | // 1-IETF RFC3261, |
| 167 | 167 | // 2-基于口令的双向认证, |
| 168 | 168 | // 3-基于数字证书的双向认证 |
| 169 | - deviceJOSNChannel.put("Status", deviceChannelExtend.getStatus() == 1 ? "ON":"OFF"); | |
| 169 | + deviceJOSNChannel.put("Status", deviceChannelExtend.isStatus() ? "ON":"OFF"); | |
| 170 | 170 | deviceJOSNChannel.put("Longitude", deviceChannelExtend.getLongitude()); |
| 171 | 171 | deviceJOSNChannel.put("Latitude", deviceChannelExtend.getLatitude()); |
| 172 | 172 | deviceJOSNChannel.put("PTZType ", deviceChannelExtend.getPTZType()); // 云台类型, 0 - 未知, 1 - 球机, 2 - 半球, | ... | ... |
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
| ... | ... | @@ -92,7 +92,7 @@ public class ApiStreamController { |
| 92 | 92 | result.put("error","device[ " + serial + " ]未找到"); |
| 93 | 93 | resultDeferredResult.setResult(result); |
| 94 | 94 | return resultDeferredResult; |
| 95 | - }else if (device.getOnline() == 0) { | |
| 95 | + }else if (!device.isOnLine()) { | |
| 96 | 96 | JSONObject result = new JSONObject(); |
| 97 | 97 | result.put("error","device[ " + code + " ]offline"); |
| 98 | 98 | resultDeferredResult.setResult(result); |
| ... | ... | @@ -113,7 +113,7 @@ public class ApiStreamController { |
| 113 | 113 | result.put("error","channel[ " + code + " ]未找到"); |
| 114 | 114 | resultDeferredResult.setResult(result); |
| 115 | 115 | return resultDeferredResult; |
| 116 | - }else if (deviceChannel.getStatus() == 0) { | |
| 116 | + }else if (!deviceChannel.isStatus()) { | |
| 117 | 117 | JSONObject result = new JSONObject(); |
| 118 | 118 | result.put("error","channel[ " + code + " ]offline"); |
| 119 | 119 | resultDeferredResult.setResult(result); | ... | ... |
src/main/java/com/genersoft/iot/vmp/web/gb28181/dto/DeviceChannelExtend.java
| ... | ... | @@ -25,7 +25,7 @@ public class DeviceChannelExtend { |
| 25 | 25 | |
| 26 | 26 | private String deviceName; |
| 27 | 27 | |
| 28 | - private int deviceOnline; | |
| 28 | + private boolean deviceOnline; | |
| 29 | 29 | |
| 30 | 30 | /** |
| 31 | 31 | * 生产厂商 |
| ... | ... | @@ -146,7 +146,7 @@ public class DeviceChannelExtend { |
| 146 | 146 | * <Status>OFF</Status> |
| 147 | 147 | * 遇到过NVR下的IPC下发信令可以推流, 但是 Status 响应 OFF |
| 148 | 148 | */ |
| 149 | - private int status; | |
| 149 | + private boolean status; | |
| 150 | 150 | |
| 151 | 151 | /** |
| 152 | 152 | * 经度 |
| ... | ... | @@ -417,11 +417,11 @@ public class DeviceChannelExtend { |
| 417 | 417 | this.PTZTypeText = PTZTypeText; |
| 418 | 418 | } |
| 419 | 419 | |
| 420 | - public int getStatus() { | |
| 420 | + public boolean isStatus() { | |
| 421 | 421 | return status; |
| 422 | 422 | } |
| 423 | 423 | |
| 424 | - public void setStatus(int status) { | |
| 424 | + public void setStatus(boolean status) { | |
| 425 | 425 | this.status = status; |
| 426 | 426 | } |
| 427 | 427 | |
| ... | ... | @@ -545,11 +545,11 @@ public class DeviceChannelExtend { |
| 545 | 545 | this.deviceName = deviceName; |
| 546 | 546 | } |
| 547 | 547 | |
| 548 | - public int getDeviceOnline() { | |
| 548 | + public boolean isDeviceOnline() { | |
| 549 | 549 | return deviceOnline; |
| 550 | 550 | } |
| 551 | 551 | |
| 552 | - public void setDeviceOnline(int deviceOnline) { | |
| 552 | + public void setDeviceOnline(boolean deviceOnline) { | |
| 553 | 553 | this.deviceOnline = deviceOnline; |
| 554 | 554 | } |
| 555 | 555 | } | ... | ... |
src/main/resources/all-application.yml
| ... | ... | @@ -44,6 +44,10 @@ spring: |
| 44 | 44 | max-lifetime: 1200000 # 是池中连接关闭后的最长生命周期(以毫秒为单位) |
| 45 | 45 | |
| 46 | 46 | |
| 47 | +# 修改分页插件为 postgresql, 数据库类型为mysql不需要 | |
| 48 | +#pagehelper: | |
| 49 | +# helper-dialect: postgresql | |
| 50 | + | |
| 47 | 51 | # [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口 |
| 48 | 52 | server: |
| 49 | 53 | port: 18080 |
| ... | ... | @@ -188,6 +192,8 @@ user-settings: |
| 188 | 192 | sip-use-source-ip-as-remote-address: false |
| 189 | 193 | # 是否开启sip日志 |
| 190 | 194 | sip-log: true |
| 195 | + # 是否开启sql日志 | |
| 196 | + sql-log: true | |
| 191 | 197 | # 收到ack消息后开始发流,默认false, 回复200ok后直接开始发流 |
| 192 | 198 | push-stream-after-ack: false |
| 193 | 199 | # 消息通道功能-缺少国标ID是否给所有上级发送消息 |
| ... | ... | @@ -200,6 +206,10 @@ user-settings: |
| 200 | 206 | device-status-notify: false |
| 201 | 207 | # 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式 |
| 202 | 208 | use-custom-ssrc-for-parent-invite: true |
| 209 | + # 国标级联离线后多久重试一次注册 | |
| 210 | + register-again-after-time: 60 | |
| 211 | + # 国标续订方式,true为续订,每次注册在同一个会话里,false为重新注册,每次使用新的会话 | |
| 212 | + register-keep-int-dialog: false | |
| 203 | 213 | # 跨域配置,配置你访问前端页面的地址即可, 可以配置多个 |
| 204 | 214 | allowed-origins: |
| 205 | 215 | - http://localhost:8008 | ... | ... |
src/main/resources/application-dev.yml
| 1 | 1 | spring: |
| 2 | + thymeleaf: | |
| 3 | + cache: false | |
| 2 | 4 | # [可选]上传文件大小限制 |
| 3 | 5 | servlet: |
| 4 | 6 | multipart: |
| ... | ... | @@ -11,18 +13,18 @@ spring: |
| 11 | 13 | # [必须修改] 端口号 |
| 12 | 14 | port: 6379 |
| 13 | 15 | # [可选] 数据库 DB |
| 14 | - database: 6 | |
| 16 | + database: 7 | |
| 15 | 17 | # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接 |
| 16 | - password: face2020 | |
| 18 | + password: | |
| 17 | 19 | # [可选] 超时时间 |
| 18 | 20 | timeout: 10000 |
| 19 | 21 | # mysql数据源 |
| 20 | 22 | datasource: |
| 21 | 23 | type: com.zaxxer.hikari.HikariDataSource |
| 22 | 24 | driver-class-name: com.mysql.cj.jdbc.Driver |
| 23 | - url: jdbc:mysql://127.0.0.1:3306/wvp2?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true | |
| 25 | + url: jdbc:mysql://127.0.0.1:3306/test_gb-89wulian?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true | |
| 24 | 26 | username: root |
| 25 | - password: 123456 | |
| 27 | + password: root | |
| 26 | 28 | hikari: |
| 27 | 29 | connection-timeout: 20000 # 是客户端等待连接池连接的最大毫秒数 |
| 28 | 30 | initialSize: 10 # 连接池初始化连接数 |
| ... | ... | @@ -30,11 +32,19 @@ spring: |
| 30 | 32 | minimum-idle: 5 # 连接池最小空闲连接数 |
| 31 | 33 | idle-timeout: 300000 # 允许连接在连接池中空闲的最长时间(以毫秒为单位) |
| 32 | 34 | max-lifetime: 1200000 # 是池中连接关闭后的最长生命周期(以毫秒为单位) |
| 33 | - | |
| 34 | - | |
| 35 | 35 | #[可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口 |
| 36 | 36 | server: |
| 37 | - port: 18080 | |
| 37 | + port: 18978 | |
| 38 | + # [可选] HTTPS配置, 默认不开启 | |
| 39 | + ssl: | |
| 40 | + # [可选] 是否开启HTTPS访问 | |
| 41 | + enabled: false | |
| 42 | + # [可选] 证书文件路径,放置在resource/目录下即可,修改xxx为文件名 | |
| 43 | + key-store: classpath:test.monitor.89iot.cn.jks | |
| 44 | + # [可选] 证书密码 | |
| 45 | + key-store-password: gpf64qmw | |
| 46 | + # [可选] 证书类型, 默认为jks,根据实际修改 | |
| 47 | + key-store-type: JKS | |
| 38 | 48 | |
| 39 | 49 | # 作为28181服务器的配置 |
| 40 | 50 | sip: |
| ... | ... | @@ -42,26 +52,36 @@ sip: |
| 42 | 52 | # 如果要监听多张网卡,可以使用逗号分隔多个IP, 例如: 192.168.1.4,10.0.0.4 |
| 43 | 53 | # 如果不明白,就使用0.0.0.0,大部分情况都是可以的 |
| 44 | 54 | # 请不要使用127.0.0.1,任何包括localhost在内的域名都是不可以的。 |
| 45 | - ip: 192.168.41.16 | |
| 55 | + ip: 192.168.1.18 | |
| 46 | 56 | # [可选] 28181服务监听的端口 |
| 47 | - port: 5060 | |
| 57 | + port: 8116 | |
| 48 | 58 | # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) |
| 49 | 59 | # 后两位为行业编码,定义参照附录D.3 |
| 50 | 60 | # 3701020049标识山东济南历下区 信息行业接入 |
| 51 | 61 | # [可选] |
| 52 | - domain: 4401020049 | |
| 62 | + domain: 4101050000 | |
| 53 | 63 | # [可选] |
| 54 | - id: 44010200492000000001 | |
| 64 | + id: 41010500002000000001 | |
| 55 | 65 | # [可选] 默认设备认证密码,后续扩展使用设备单独密码, 移除密码将不进行校验 |
| 56 | - password: admin123 | |
| 66 | + password: bajiuwulian1006 | |
| 67 | + # 是否存储alarm信息 | |
| 68 | + alarm: true | |
| 57 | 69 | |
| 58 | 70 | #zlm 默认服务器配置 |
| 59 | 71 | media: |
| 60 | - id: FQ3TF8yT83wh5Wvz | |
| 72 | + id: 89wulian-one | |
| 61 | 73 | # [必须修改] zlm服务器的内网IP |
| 62 | - ip: 192.168.41.16 | |
| 74 | + ip: 192.168.1.18 | |
| 63 | 75 | # [必须修改] zlm服务器的http.port |
| 64 | - http-port: 8091 | |
| 76 | + http-port: 80 | |
| 77 | + # [可选] 返回流地址时的ip,置空使用 media.ip | |
| 78 | + stream-ip: 192.168.1.18 | |
| 79 | + # [可选] wvp在国标信令中使用的ip,此ip为摄像机可以访问到的ip, 置空使用 media.ip | |
| 80 | + sdp-ip: 192.168.1.18 | |
| 81 | + # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip | |
| 82 | + hook-ip: 192.168.1.18 | |
| 83 | + # [可选] zlm服务器的http.sslport, 置空使用zlm配置文件配置 | |
| 84 | + http-ssl-port: 443 | |
| 65 | 85 | # [可选] zlm服务器的hook.admin_params=secret |
| 66 | 86 | secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc |
| 67 | 87 | # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 |
| ... | ... | @@ -69,11 +89,24 @@ media: |
| 69 | 89 | # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输 |
| 70 | 90 | enable: true |
| 71 | 91 | # [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性,不然自动配置此属性可能不成功 |
| 72 | - port-range: 30000,30500 # 端口范围 | |
| 92 | + port-range: 50000,50300 # 端口范围 | |
| 73 | 93 | # [可选] 国标级联在此范围内选择端口发送媒体流, |
| 74 | - send-port-range: 30000,30500 # 端口范围 | |
| 94 | + send-port-range: 50000,50300 # 端口范围 | |
| 75 | 95 | # 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载, 0 表示不使用 |
| 76 | 96 | record-assist-port: 18081 |
| 97 | +# [根据业务需求配置] | |
| 98 | +user-settings: | |
| 99 | + # 点播/录像回放 等待超时时间,单位:毫秒 | |
| 100 | + play-timeout: 180000 | |
| 101 | + # [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播, 需要rtp.enable=true | |
| 102 | + auto-apply-play: true | |
| 103 | + # 设备/通道状态变化时发送消息 | |
| 104 | + device-status-notify: true | |
| 105 | + # 跨域配置,配置你访问前端页面的地址即可, 可以配置多个 | |
| 106 | + allowed-origins: | |
| 107 | + - http://localhost:8080 | |
| 108 | + - http://127.0.0.1:8080 | |
| 77 | 109 | # [可选] 日志配置, 一般不需要改 |
| 78 | 110 | logging: |
| 79 | 111 | config: classpath:logback-spring-local.xml |
| 112 | + | ... | ... |
src/main/resources/civilCode.csv
0 → 100644
| 1 | +编号,名称,上级 | |
| 2 | +11,北京市, | |
| 3 | +110101,东城区,11 | |
| 4 | +110102,西城区,11 | |
| 5 | +110105,朝阳区,11 | |
| 6 | +110106,丰台区,11 | |
| 7 | +110107,石景山区,11 | |
| 8 | +110108,海淀区,11 | |
| 9 | +110109,门头沟区,11 | |
| 10 | +110111,房山区,11 | |
| 11 | +110112,通州区,11 | |
| 12 | +110113,顺义区,11 | |
| 13 | +110114,昌平区,11 | |
| 14 | +110115,大兴区,11 | |
| 15 | +110116,怀柔区,11 | |
| 16 | +110117,平谷区,11 | |
| 17 | +110118,密云区,11 | |
| 18 | +110119,延庆区,11 | |
| 19 | +12,天津市, | |
| 20 | +120101,和平区,12 | |
| 21 | +120102,河东区,12 | |
| 22 | +120103,河西区,12 | |
| 23 | +120104,南开区,12 | |
| 24 | +120105,河北区,12 | |
| 25 | +120106,红桥区,12 | |
| 26 | +120110,东丽区,12 | |
| 27 | +120111,西青区,12 | |
| 28 | +120112,津南区,12 | |
| 29 | +120113,北辰区,12 | |
| 30 | +120114,武清区,12 | |
| 31 | +120115,宝坻区,12 | |
| 32 | +120116,滨海新区,12 | |
| 33 | +120117,宁河区,12 | |
| 34 | +120118,静海区,12 | |
| 35 | +120119,蓟州区,12 | |
| 36 | +13,河北省, | |
| 37 | +1301,石家庄市,13 | |
| 38 | +130102,长安区,1301 | |
| 39 | +130104,桥西区,1301 | |
| 40 | +130105,新华区,1301 | |
| 41 | +130107,井陉矿区,1301 | |
| 42 | +130108,裕华区,1301 | |
| 43 | +130109,藁城区,1301 | |
| 44 | +130110,鹿泉区,1301 | |
| 45 | +130111,栾城区,1301 | |
| 46 | +130121,井陉县,1301 | |
| 47 | +130123,正定县,1301 | |
| 48 | +130125,行唐县,1301 | |
| 49 | +130126,灵寿县,1301 | |
| 50 | +130127,高邑县,1301 | |
| 51 | +130128,深泽县,1301 | |
| 52 | +130129,赞皇县,1301 | |
| 53 | +130130,无极县,1301 | |
| 54 | +130131,平山县,1301 | |
| 55 | +130132,元氏县,1301 | |
| 56 | +130133,赵县,1301 | |
| 57 | +130181,辛集市,1301 | |
| 58 | +130183,晋州市,1301 | |
| 59 | +130184,新乐市,1301 | |
| 60 | +1302,唐山市,13 | |
| 61 | +130202,路南区,1302 | |
| 62 | +130203,路北区,1302 | |
| 63 | +130204,古冶区,1302 | |
| 64 | +130205,开平区,1302 | |
| 65 | +130207,丰南区,1302 | |
| 66 | +130208,丰润区,1302 | |
| 67 | +130209,曹妃甸区,1302 | |
| 68 | +130224,滦南县,1302 | |
| 69 | +130225,乐亭县,1302 | |
| 70 | +130227,迁西县,1302 | |
| 71 | +130229,玉田县,1302 | |
| 72 | +130281,遵化市,1302 | |
| 73 | +130283,迁安市,1302 | |
| 74 | +130284,滦州市,1302 | |
| 75 | +1303,秦皇岛市,13 | |
| 76 | +130302,海港区,1303 | |
| 77 | +130303,山海关区,1303 | |
| 78 | +130304,北戴河区,1303 | |
| 79 | +130306,抚宁区,1303 | |
| 80 | +130321,青龙满族自治县,1303 | |
| 81 | +130322,昌黎县,1303 | |
| 82 | +130324,卢龙县,1303 | |
| 83 | +1304,邯郸市,13 | |
| 84 | +130402,邯山区,1304 | |
| 85 | +130403,丛台区,1304 | |
| 86 | +130404,复兴区,1304 | |
| 87 | +130406,峰峰矿区,1304 | |
| 88 | +130407,肥乡区,1304 | |
| 89 | +130408,永年区,1304 | |
| 90 | +130423,临漳县,1304 | |
| 91 | +130424,成安县,1304 | |
| 92 | +130425,大名县,1304 | |
| 93 | +130426,涉县,1304 | |
| 94 | +130427,磁县,1304 | |
| 95 | +130430,邱县,1304 | |
| 96 | +130431,鸡泽县,1304 | |
| 97 | +130432,广平县,1304 | |
| 98 | +130433,馆陶县,1304 | |
| 99 | +130434,魏县,1304 | |
| 100 | +130435,曲周县,1304 | |
| 101 | +130481,武安市,1304 | |
| 102 | +1305,邢台市,13 | |
| 103 | +130502,桥东区,1305 | |
| 104 | +130503,桥西区,1305 | |
| 105 | +130521,邢台县,1305 | |
| 106 | +130522,临城县,1305 | |
| 107 | +130523,内丘县,1305 | |
| 108 | +130524,柏乡县,1305 | |
| 109 | +130525,隆尧县,1305 | |
| 110 | +130526,任县,1305 | |
| 111 | +130527,南和县,1305 | |
| 112 | +130528,宁晋县,1305 | |
| 113 | +130529,巨鹿县,1305 | |
| 114 | +130530,新河县,1305 | |
| 115 | +130531,广宗县,1305 | |
| 116 | +130532,平乡县,1305 | |
| 117 | +130533,威县,1305 | |
| 118 | +130534,清河县,1305 | |
| 119 | +130535,临西县,1305 | |
| 120 | +130581,南宫市,1305 | |
| 121 | +130582,沙河市,1305 | |
| 122 | +1306,保定市,13 | |
| 123 | +130602,竞秀区,1306 | |
| 124 | +130606,莲池区,1306 | |
| 125 | +130607,满城区,1306 | |
| 126 | +130608,清苑区,1306 | |
| 127 | +130609,徐水区,1306 | |
| 128 | +130623,涞水县,1306 | |
| 129 | +130624,阜平县,1306 | |
| 130 | +130626,定兴县,1306 | |
| 131 | +130627,唐县,1306 | |
| 132 | +130628,高阳县,1306 | |
| 133 | +130629,容城县,1306 | |
| 134 | +130630,涞源县,1306 | |
| 135 | +130631,望都县,1306 | |
| 136 | +130632,安新县,1306 | |
| 137 | +130633,易县,1306 | |
| 138 | +130634,曲阳县,1306 | |
| 139 | +130635,蠡县,1306 | |
| 140 | +130636,顺平县,1306 | |
| 141 | +130637,博野县,1306 | |
| 142 | +130638,雄县,1306 | |
| 143 | +130681,涿州市,1306 | |
| 144 | +130682,定州市,1306 | |
| 145 | +130683,安国市,1306 | |
| 146 | +130684,高碑店市,1306 | |
| 147 | +1307,张家口市,13 | |
| 148 | +130702,桥东区,1307 | |
| 149 | +130703,桥西区,1307 | |
| 150 | +130705,宣化区,1307 | |
| 151 | +130706,下花园区,1307 | |
| 152 | +130708,万全区,1307 | |
| 153 | +130709,崇礼区,1307 | |
| 154 | +130722,张北县,1307 | |
| 155 | +130723,康保县,1307 | |
| 156 | +130724,沽源县,1307 | |
| 157 | +130725,尚义县,1307 | |
| 158 | +130726,蔚县,1307 | |
| 159 | +130727,阳原县,1307 | |
| 160 | +130728,怀安县,1307 | |
| 161 | +130730,怀来县,1307 | |
| 162 | +130731,涿鹿县,1307 | |
| 163 | +130732,赤城县,1307 | |
| 164 | +1308,承德市,13 | |
| 165 | +130802,双桥区,1308 | |
| 166 | +130803,双滦区,1308 | |
| 167 | +130804,鹰手营子矿区,1308 | |
| 168 | +130821,承德县,1308 | |
| 169 | +130822,兴隆县,1308 | |
| 170 | +130824,滦平县,1308 | |
| 171 | +130825,隆化县,1308 | |
| 172 | +130826,丰宁满族自治县,1308 | |
| 173 | +130827,宽城满族自治县,1308 | |
| 174 | +130828,围场满族蒙古族自治县,1308 | |
| 175 | +130881,平泉市,1308 | |
| 176 | +1309,沧州市,13 | |
| 177 | +130902,新华区,1309 | |
| 178 | +130903,运河区,1309 | |
| 179 | +130921,沧县,1309 | |
| 180 | +130922,青县,1309 | |
| 181 | +130923,东光县,1309 | |
| 182 | +130924,海兴县,1309 | |
| 183 | +130925,盐山县,1309 | |
| 184 | +130926,肃宁县,1309 | |
| 185 | +130927,南皮县,1309 | |
| 186 | +130928,吴桥县,1309 | |
| 187 | +130929,献县,1309 | |
| 188 | +130930,孟村回族自治县,1309 | |
| 189 | +130981,泊头市,1309 | |
| 190 | +130982,任丘市,1309 | |
| 191 | +130983,黄骅市,1309 | |
| 192 | +130984,河间市,1309 | |
| 193 | +1310,廊坊市,13 | |
| 194 | +131002,安次区,1310 | |
| 195 | +131003,广阳区,1310 | |
| 196 | +131022,固安县,1310 | |
| 197 | +131023,永清县,1310 | |
| 198 | +131024,香河县,1310 | |
| 199 | +131025,大城县,1310 | |
| 200 | +131026,文安县,1310 | |
| 201 | +131028,大厂回族自治县,1310 | |
| 202 | +131081,霸州市,1310 | |
| 203 | +131082,三河市,1310 | |
| 204 | +1311,衡水市,13 | |
| 205 | +131102,桃城区,1311 | |
| 206 | +131103,冀州区,1311 | |
| 207 | +131121,枣强县,1311 | |
| 208 | +131122,武邑县,1311 | |
| 209 | +131123,武强县,1311 | |
| 210 | +131124,饶阳县,1311 | |
| 211 | +131125,安平县,1311 | |
| 212 | +131126,故城县,1311 | |
| 213 | +131127,景县,1311 | |
| 214 | +131128,阜城县,1311 | |
| 215 | +131182,深州市,1311 | |
| 216 | +14,山西省, | |
| 217 | +1401,太原市,14 | |
| 218 | +140105,小店区,1401 | |
| 219 | +140106,迎泽区,1401 | |
| 220 | +140107,杏花岭区,1401 | |
| 221 | +140108,尖草坪区,1401 | |
| 222 | +140109,万柏林区,1401 | |
| 223 | +140110,晋源区,1401 | |
| 224 | +140121,清徐县,1401 | |
| 225 | +140122,阳曲县,1401 | |
| 226 | +140123,娄烦县,1401 | |
| 227 | +140181,古交市,1401 | |
| 228 | +1402,大同市,14 | |
| 229 | +140212,新荣区,1402 | |
| 230 | +140213,平城区,1402 | |
| 231 | +140214,云冈区,1402 | |
| 232 | +140215,云州区,1402 | |
| 233 | +140221,阳高县,1402 | |
| 234 | +140222,天镇县,1402 | |
| 235 | +140223,广灵县,1402 | |
| 236 | +140224,灵丘县,1402 | |
| 237 | +140225,浑源县,1402 | |
| 238 | +140226,左云县,1402 | |
| 239 | +1403,阳泉市,14 | |
| 240 | +140302,城区,1403 | |
| 241 | +140303,矿区,1403 | |
| 242 | +140311,郊区,1403 | |
| 243 | +140321,平定县,1403 | |
| 244 | +140322,盂县,1403 | |
| 245 | +1404,长治市,14 | |
| 246 | +140403,潞州区,1404 | |
| 247 | +140404,上党区,1404 | |
| 248 | +140405,屯留区,1404 | |
| 249 | +140406,潞城区,1404 | |
| 250 | +140423,襄垣县,1404 | |
| 251 | +140425,平顺县,1404 | |
| 252 | +140426,黎城县,1404 | |
| 253 | +140427,壶关县,1404 | |
| 254 | +140428,长子县,1404 | |
| 255 | +140429,武乡县,1404 | |
| 256 | +140430,沁县,1404 | |
| 257 | +140431,沁源县,1404 | |
| 258 | +1405,晋城市,14 | |
| 259 | +140502,城区,1405 | |
| 260 | +140521,沁水县,1405 | |
| 261 | +140522,阳城县,1405 | |
| 262 | +140524,陵川县,1405 | |
| 263 | +140525,泽州县,1405 | |
| 264 | +140581,高平市,1405 | |
| 265 | +1406,朔州市,14 | |
| 266 | +140602,朔城区,1406 | |
| 267 | +140603,平鲁区,1406 | |
| 268 | +140621,山阴县,1406 | |
| 269 | +140622,应县,1406 | |
| 270 | +140623,右玉县,1406 | |
| 271 | +140681,怀仁市,1406 | |
| 272 | +1407,晋中市,14 | |
| 273 | +140702,榆次区,1407 | |
| 274 | +140721,榆社县,1407 | |
| 275 | +140722,左权县,1407 | |
| 276 | +140723,和顺县,1407 | |
| 277 | +140724,昔阳县,1407 | |
| 278 | +140725,寿阳县,1407 | |
| 279 | +140726,太谷县,1407 | |
| 280 | +140727,祁县,1407 | |
| 281 | +140728,平遥县,1407 | |
| 282 | +140729,灵石县,1407 | |
| 283 | +140781,介休市,1407 | |
| 284 | +1408,运城市,14 | |
| 285 | +140802,盐湖区,1408 | |
| 286 | +140821,临猗县,1408 | |
| 287 | +140822,万荣县,1408 | |
| 288 | +140823,闻喜县,1408 | |
| 289 | +140824,稷山县,1408 | |
| 290 | +140825,新绛县,1408 | |
| 291 | +140826,绛县,1408 | |
| 292 | +140827,垣曲县,1408 | |
| 293 | +140828,夏县,1408 | |
| 294 | +140829,平陆县,1408 | |
| 295 | +140830,芮城县,1408 | |
| 296 | +140881,永济市,1408 | |
| 297 | +140882,河津市,1408 | |
| 298 | +1409,忻州市,14 | |
| 299 | +140902,忻府区,1409 | |
| 300 | +140921,定襄县,1409 | |
| 301 | +140922,五台县,1409 | |
| 302 | +140923,代县,1409 | |
| 303 | +140924,繁峙县,1409 | |
| 304 | +140925,宁武县,1409 | |
| 305 | +140926,静乐县,1409 | |
| 306 | +140927,神池县,1409 | |
| 307 | +140928,五寨县,1409 | |
| 308 | +140929,岢岚县,1409 | |
| 309 | +140930,河曲县,1409 | |
| 310 | +140931,保德县,1409 | |
| 311 | +140932,偏关县,1409 | |
| 312 | +140981,原平市,1409 | |
| 313 | +1410,临汾市,14 | |
| 314 | +141002,尧都区,1410 | |
| 315 | +141021,曲沃县,1410 | |
| 316 | +141022,翼城县,1410 | |
| 317 | +141023,襄汾县,1410 | |
| 318 | +141024,洪洞县,1410 | |
| 319 | +141025,古县,1410 | |
| 320 | +141026,安泽县,1410 | |
| 321 | +141027,浮山县,1410 | |
| 322 | +141028,吉县,1410 | |
| 323 | +141029,乡宁县,1410 | |
| 324 | +141030,大宁县,1410 | |
| 325 | +141031,隰县,1410 | |
| 326 | +141032,永和县,1410 | |
| 327 | +141033,蒲县,1410 | |
| 328 | +141034,汾西县,1410 | |
| 329 | +141081,侯马市,1410 | |
| 330 | +141082,霍州市,1410 | |
| 331 | +1411,吕梁市,14 | |
| 332 | +141102,离石区,1411 | |
| 333 | +141121,文水县,1411 | |
| 334 | +141122,交城县,1411 | |
| 335 | +141123,兴县,1411 | |
| 336 | +141124,临县,1411 | |
| 337 | +141125,柳林县,1411 | |
| 338 | +141126,石楼县,1411 | |
| 339 | +141127,岚县,1411 | |
| 340 | +141128,方山县,1411 | |
| 341 | +141129,中阳县,1411 | |
| 342 | +141130,交口县,1411 | |
| 343 | +141181,孝义市,1411 | |
| 344 | +141182,汾阳市,1411 | |
| 345 | +15,内蒙古自治区, | |
| 346 | +1501,呼和浩特市,15 | |
| 347 | +150102,新城区,1501 | |
| 348 | +150103,回民区,1501 | |
| 349 | +150104,玉泉区,1501 | |
| 350 | +150105,赛罕区,1501 | |
| 351 | +150121,土默特左旗,1501 | |
| 352 | +150122,托克托县,1501 | |
| 353 | +150123,和林格尔县,1501 | |
| 354 | +150124,清水河县,1501 | |
| 355 | +150125,武川县,1501 | |
| 356 | +1502,包头市,15 | |
| 357 | +150202,东河区,1502 | |
| 358 | +150203,昆都仑区,1502 | |
| 359 | +150204,青山区,1502 | |
| 360 | +150205,石拐区,1502 | |
| 361 | +150206,白云鄂博矿区,1502 | |
| 362 | +150207,九原区,1502 | |
| 363 | +150221,土默特右旗,1502 | |
| 364 | +150222,固阳县,1502 | |
| 365 | +150223,达尔罕茂明安联合旗,1502 | |
| 366 | +1503,乌海市,15 | |
| 367 | +150302,海勃湾区,1503 | |
| 368 | +150303,海南区,1503 | |
| 369 | +150304,乌达区,1503 | |
| 370 | +1504,赤峰市,15 | |
| 371 | +150402,红山区,1504 | |
| 372 | +150403,元宝山区,1504 | |
| 373 | +150404,松山区,1504 | |
| 374 | +150421,阿鲁科尔沁旗,1504 | |
| 375 | +150422,巴林左旗,1504 | |
| 376 | +150423,巴林右旗,1504 | |
| 377 | +150424,林西县,1504 | |
| 378 | +150425,克什克腾旗,1504 | |
| 379 | +150426,翁牛特旗,1504 | |
| 380 | +150428,喀喇沁旗,1504 | |
| 381 | +150429,宁城县,1504 | |
| 382 | +150430,敖汉旗,1504 | |
| 383 | +1505,通辽市,15 | |
| 384 | +150502,科尔沁区,1505 | |
| 385 | +150521,科尔沁左翼中旗,1505 | |
| 386 | +150522,科尔沁左翼后旗,1505 | |
| 387 | +150523,开鲁县,1505 | |
| 388 | +150524,库伦旗,1505 | |
| 389 | +150525,奈曼旗,1505 | |
| 390 | +150526,扎鲁特旗,1505 | |
| 391 | +150581,霍林郭勒市,1505 | |
| 392 | +1506,鄂尔多斯市,15 | |
| 393 | +150602,东胜区,1506 | |
| 394 | +150603,康巴什区,1506 | |
| 395 | +150621,达拉特旗,1506 | |
| 396 | +150622,准格尔旗,1506 | |
| 397 | +150623,鄂托克前旗,1506 | |
| 398 | +150624,鄂托克旗,1506 | |
| 399 | +150625,杭锦旗,1506 | |
| 400 | +150626,乌审旗,1506 | |
| 401 | +150627,伊金霍洛旗,1506 | |
| 402 | +1507,呼伦贝尔市,15 | |
| 403 | +150702,海拉尔区,1507 | |
| 404 | +150703,扎赉诺尔区,1507 | |
| 405 | +150721,阿荣旗,1507 | |
| 406 | +150722,莫力达瓦达斡尔族自治旗,1507 | |
| 407 | +150723,鄂伦春自治旗,1507 | |
| 408 | +150724,鄂温克族自治旗,1507 | |
| 409 | +150725,陈巴尔虎旗,1507 | |
| 410 | +150726,新巴尔虎左旗,1507 | |
| 411 | +150727,新巴尔虎右旗,1507 | |
| 412 | +150781,满洲里市,1507 | |
| 413 | +150782,牙克石市,1507 | |
| 414 | +150783,扎兰屯市,1507 | |
| 415 | +150784,额尔古纳市,1507 | |
| 416 | +150785,根河市,1507 | |
| 417 | +1508,巴彦淖尔市,15 | |
| 418 | +150802,临河区,1508 | |
| 419 | +150821,五原县,1508 | |
| 420 | +150822,磴口县,1508 | |
| 421 | +150823,乌拉特前旗,1508 | |
| 422 | +150824,乌拉特中旗,1508 | |
| 423 | +150825,乌拉特后旗,1508 | |
| 424 | +150826,杭锦后旗,1508 | |
| 425 | +1509,乌兰察布市,15 | |
| 426 | +150902,集宁区,1509 | |
| 427 | +150921,卓资县,1509 | |
| 428 | +150922,化德县,1509 | |
| 429 | +150923,商都县,1509 | |
| 430 | +150924,兴和县,1509 | |
| 431 | +150925,凉城县,1509 | |
| 432 | +150926,察哈尔右翼前旗,1509 | |
| 433 | +150927,察哈尔右翼中旗,1509 | |
| 434 | +150928,察哈尔右翼后旗,1509 | |
| 435 | +150929,四子王旗,1509 | |
| 436 | +150981,丰镇市,1509 | |
| 437 | +1522,兴安盟,15 | |
| 438 | +152201,乌兰浩特市,1522 | |
| 439 | +152202,阿尔山市,1522 | |
| 440 | +152221,科尔沁右翼前旗,1522 | |
| 441 | +152222,科尔沁右翼中旗,1522 | |
| 442 | +152223,扎赉特旗,1522 | |
| 443 | +152224,突泉县,1522 | |
| 444 | +1525,锡林郭勒盟,15 | |
| 445 | +152501,二连浩特市,1525 | |
| 446 | +152502,锡林浩特市,1525 | |
| 447 | +152522,阿巴嘎旗,1525 | |
| 448 | +152523,苏尼特左旗,1525 | |
| 449 | +152524,苏尼特右旗,1525 | |
| 450 | +152525,东乌珠穆沁旗,1525 | |
| 451 | +152526,西乌珠穆沁旗,1525 | |
| 452 | +152527,太仆寺旗,1525 | |
| 453 | +152528,镶黄旗,1525 | |
| 454 | +152529,正镶白旗,1525 | |
| 455 | +152530,正蓝旗,1525 | |
| 456 | +152531,多伦县,1525 | |
| 457 | +1529,阿拉善盟,15 | |
| 458 | +152921,阿拉善左旗,1529 | |
| 459 | +152922,阿拉善右旗,1529 | |
| 460 | +152923,额济纳旗,1529 | |
| 461 | +21,辽宁省, | |
| 462 | +2101,沈阳市,21 | |
| 463 | +210102,和平区,2101 | |
| 464 | +210103,沈河区,2101 | |
| 465 | +210104,大东区,2101 | |
| 466 | +210105,皇姑区,2101 | |
| 467 | +210106,铁西区,2101 | |
| 468 | +210111,苏家屯区,2101 | |
| 469 | +210112,浑南区,2101 | |
| 470 | +210113,沈北新区,2101 | |
| 471 | +210114,于洪区,2101 | |
| 472 | +210115,辽中区,2101 | |
| 473 | +210123,康平县,2101 | |
| 474 | +210124,法库县,2101 | |
| 475 | +210181,新民市,2101 | |
| 476 | +2102,大连市,21 | |
| 477 | +210202,中山区,2102 | |
| 478 | +210203,西岗区,2102 | |
| 479 | +210204,沙河口区,2102 | |
| 480 | +210211,甘井子区,2102 | |
| 481 | +210212,旅顺口区,2102 | |
| 482 | +210213,金州区,2102 | |
| 483 | +210214,普兰店区,2102 | |
| 484 | +210224,长海县,2102 | |
| 485 | +210281,瓦房店市,2102 | |
| 486 | +210283,庄河市,2102 | |
| 487 | +2103,鞍山市,21 | |
| 488 | +210302,铁东区,2103 | |
| 489 | +210303,铁西区,2103 | |
| 490 | +210304,立山区,2103 | |
| 491 | +210311,千山区,2103 | |
| 492 | +210321,台安县,2103 | |
| 493 | +210323,岫岩满族自治县,2103 | |
| 494 | +210381,海城市,2103 | |
| 495 | +2104,抚顺市,21 | |
| 496 | +210402,新抚区,2104 | |
| 497 | +210403,东洲区,2104 | |
| 498 | +210404,望花区,2104 | |
| 499 | +210411,顺城区,2104 | |
| 500 | +210421,抚顺县,2104 | |
| 501 | +210422,新宾满族自治县,2104 | |
| 502 | +210423,清原满族自治县,2104 | |
| 503 | +2105,本溪市,21 | |
| 504 | +210502,平山区,2105 | |
| 505 | +210503,溪湖区,2105 | |
| 506 | +210504,明山区,2105 | |
| 507 | +210505,南芬区,2105 | |
| 508 | +210521,本溪满族自治县,2105 | |
| 509 | +210522,桓仁满族自治县,2105 | |
| 510 | +2106,丹东市,21 | |
| 511 | +210602,元宝区,2106 | |
| 512 | +210603,振兴区,2106 | |
| 513 | +210604,振安区,2106 | |
| 514 | +210624,宽甸满族自治县,2106 | |
| 515 | +210681,东港市,2106 | |
| 516 | +210682,凤城市,2106 | |
| 517 | +2107,锦州市,21 | |
| 518 | +210702,古塔区,2107 | |
| 519 | +210703,凌河区,2107 | |
| 520 | +210711,太和区,2107 | |
| 521 | +210726,黑山县,2107 | |
| 522 | +210727,义县,2107 | |
| 523 | +210781,凌海市,2107 | |
| 524 | +210782,北镇市,2107 | |
| 525 | +2108,营口市,21 | |
| 526 | +210802,站前区,2108 | |
| 527 | +210803,西市区,2108 | |
| 528 | +210804,鲅鱼圈区,2108 | |
| 529 | +210811,老边区,2108 | |
| 530 | +210881,盖州市,2108 | |
| 531 | +210882,大石桥市,2108 | |
| 532 | +2109,阜新市,21 | |
| 533 | +210902,海州区,2109 | |
| 534 | +210903,新邱区,2109 | |
| 535 | +210904,太平区,2109 | |
| 536 | +210905,清河门区,2109 | |
| 537 | +210911,细河区,2109 | |
| 538 | +210921,阜新蒙古族自治县,2109 | |
| 539 | +210922,彰武县,2109 | |
| 540 | +2110,辽阳市,21 | |
| 541 | +211002,白塔区,2110 | |
| 542 | +211003,文圣区,2110 | |
| 543 | +211004,宏伟区,2110 | |
| 544 | +211005,弓长岭区,2110 | |
| 545 | +211011,太子河区,2110 | |
| 546 | +211021,辽阳县,2110 | |
| 547 | +211081,灯塔市,2110 | |
| 548 | +2111,盘锦市,21 | |
| 549 | +211102,双台子区,2111 | |
| 550 | +211103,兴隆台区,2111 | |
| 551 | +211104,大洼区,2111 | |
| 552 | +211122,盘山县,2111 | |
| 553 | +2112,铁岭市,21 | |
| 554 | +211202,银州区,2112 | |
| 555 | +211204,清河区,2112 | |
| 556 | +211221,铁岭县,2112 | |
| 557 | +211223,西丰县,2112 | |
| 558 | +211224,昌图县,2112 | |
| 559 | +211281,调兵山市,2112 | |
| 560 | +211282,开原市,2112 | |
| 561 | +2113,朝阳市,21 | |
| 562 | +211302,双塔区,2113 | |
| 563 | +211303,龙城区,2113 | |
| 564 | +211321,朝阳县,2113 | |
| 565 | +211322,建平县,2113 | |
| 566 | +211324,喀喇沁左翼蒙古族自治县,2113 | |
| 567 | +211381,北票市,2113 | |
| 568 | +211382,凌源市,2113 | |
| 569 | +2114,葫芦岛市,21 | |
| 570 | +211402,连山区,2114 | |
| 571 | +211403,龙港区,2114 | |
| 572 | +211404,南票区,2114 | |
| 573 | +211421,绥中县,2114 | |
| 574 | +211422,建昌县,2114 | |
| 575 | +211481,兴城市,2114 | |
| 576 | +22,吉林省, | |
| 577 | +2201,长春市,22 | |
| 578 | +220102,南关区,2201 | |
| 579 | +220103,宽城区,2201 | |
| 580 | +220104,朝阳区,2201 | |
| 581 | +220105,二道区,2201 | |
| 582 | +220106,绿园区,2201 | |
| 583 | +220112,双阳区,2201 | |
| 584 | +220113,九台区,2201 | |
| 585 | +220122,农安县,2201 | |
| 586 | +220182,榆树市,2201 | |
| 587 | +220183,德惠市,2201 | |
| 588 | +2202,吉林市,22 | |
| 589 | +220202,昌邑区,2202 | |
| 590 | +220203,龙潭区,2202 | |
| 591 | +220204,船营区,2202 | |
| 592 | +220211,丰满区,2202 | |
| 593 | +220221,永吉县,2202 | |
| 594 | +220281,蛟河市,2202 | |
| 595 | +220282,桦甸市,2202 | |
| 596 | +220283,舒兰市,2202 | |
| 597 | +220284,磐石市,2202 | |
| 598 | +2203,四平市,22 | |
| 599 | +220302,铁西区,2203 | |
| 600 | +220303,铁东区,2203 | |
| 601 | +220322,梨树县,2203 | |
| 602 | +220323,伊通满族自治县,2203 | |
| 603 | +220381,公主岭市,2203 | |
| 604 | +220382,双辽市,2203 | |
| 605 | +2204,辽源市,22 | |
| 606 | +220402,龙山区,2204 | |
| 607 | +220403,西安区,2204 | |
| 608 | +220421,东丰县,2204 | |
| 609 | +220422,东辽县,2204 | |
| 610 | +2205,通化市,22 | |
| 611 | +220502,东昌区,2205 | |
| 612 | +220503,二道江区,2205 | |
| 613 | +220521,通化县,2205 | |
| 614 | +220523,辉南县,2205 | |
| 615 | +220524,柳河县,2205 | |
| 616 | +220581,梅河口市,2205 | |
| 617 | +220582,集安市,2205 | |
| 618 | +2206,白山市,22 | |
| 619 | +220602,浑江区,2206 | |
| 620 | +220605,江源区,2206 | |
| 621 | +220621,抚松县,2206 | |
| 622 | +220622,靖宇县,2206 | |
| 623 | +220623,长白朝鲜族自治县,2206 | |
| 624 | +220681,临江市,2206 | |
| 625 | +2207,松原市,22 | |
| 626 | +220702,宁江区,2207 | |
| 627 | +220721,前郭尔罗斯蒙古族自治县,2207 | |
| 628 | +220722,长岭县,2207 | |
| 629 | +220723,乾安县,2207 | |
| 630 | +220781,扶余市,2207 | |
| 631 | +2208,白城市,22 | |
| 632 | +220802,洮北区,2208 | |
| 633 | +220821,镇赉县,2208 | |
| 634 | +220822,通榆县,2208 | |
| 635 | +220881,洮南市,2208 | |
| 636 | +220882,大安市,2208 | |
| 637 | +2224,延边朝鲜族自治州,22 | |
| 638 | +222401,延吉市,2224 | |
| 639 | +222402,图们市,2224 | |
| 640 | +222403,敦化市,2224 | |
| 641 | +222404,珲春市,2224 | |
| 642 | +222405,龙井市,2224 | |
| 643 | +222406,和龙市,2224 | |
| 644 | +222424,汪清县,2224 | |
| 645 | +222426,安图县,2224 | |
| 646 | +23,黑龙江省, | |
| 647 | +2301,哈尔滨市,23 | |
| 648 | +230102,道里区,2301 | |
| 649 | +230103,南岗区,2301 | |
| 650 | +230104,道外区,2301 | |
| 651 | +230108,平房区,2301 | |
| 652 | +230109,松北区,2301 | |
| 653 | +230110,香坊区,2301 | |
| 654 | +230111,呼兰区,2301 | |
| 655 | +230112,阿城区,2301 | |
| 656 | +230113,双城区,2301 | |
| 657 | +230123,依兰县,2301 | |
| 658 | +230124,方正县,2301 | |
| 659 | +230125,宾县,2301 | |
| 660 | +230126,巴彦县,2301 | |
| 661 | +230127,木兰县,2301 | |
| 662 | +230128,通河县,2301 | |
| 663 | +230129,延寿县,2301 | |
| 664 | +230183,尚志市,2301 | |
| 665 | +230184,五常市,2301 | |
| 666 | +2302,齐齐哈尔市,23 | |
| 667 | +230202,龙沙区,2302 | |
| 668 | +230203,建华区,2302 | |
| 669 | +230204,铁锋区,2302 | |
| 670 | +230205,昂昂溪区,2302 | |
| 671 | +230206,富拉尔基区,2302 | |
| 672 | +230207,碾子山区,2302 | |
| 673 | +230208,梅里斯达斡尔族区,2302 | |
| 674 | +230221,龙江县,2302 | |
| 675 | +230223,依安县,2302 | |
| 676 | +230224,泰来县,2302 | |
| 677 | +230225,甘南县,2302 | |
| 678 | +230227,富裕县,2302 | |
| 679 | +230229,克山县,2302 | |
| 680 | +230230,克东县,2302 | |
| 681 | +230231,拜泉县,2302 | |
| 682 | +230281,讷河市,2302 | |
| 683 | +2303,鸡西市,23 | |
| 684 | +230302,鸡冠区,2303 | |
| 685 | +230303,恒山区,2303 | |
| 686 | +230304,滴道区,2303 | |
| 687 | +230305,梨树区,2303 | |
| 688 | +230306,城子河区,2303 | |
| 689 | +230307,麻山区,2303 | |
| 690 | +230321,鸡东县,2303 | |
| 691 | +230381,虎林市,2303 | |
| 692 | +230382,密山市,2303 | |
| 693 | +2304,鹤岗市,23 | |
| 694 | +230402,向阳区,2304 | |
| 695 | +230403,工农区,2304 | |
| 696 | +230404,南山区,2304 | |
| 697 | +230405,兴安区,2304 | |
| 698 | +230406,东山区,2304 | |
| 699 | +230407,兴山区,2304 | |
| 700 | +230421,萝北县,2304 | |
| 701 | +230422,绥滨县,2304 | |
| 702 | +2305,双鸭山市,23 | |
| 703 | +230502,尖山区,2305 | |
| 704 | +230503,岭东区,2305 | |
| 705 | +230505,四方台区,2305 | |
| 706 | +230506,宝山区,2305 | |
| 707 | +230521,集贤县,2305 | |
| 708 | +230522,友谊县,2305 | |
| 709 | +230523,宝清县,2305 | |
| 710 | +230524,饶河县,2305 | |
| 711 | +2306,大庆市,23 | |
| 712 | +230602,萨尔图区,2306 | |
| 713 | +230603,龙凤区,2306 | |
| 714 | +230604,让胡路区,2306 | |
| 715 | +230605,红岗区,2306 | |
| 716 | +230606,大同区,2306 | |
| 717 | +230621,肇州县,2306 | |
| 718 | +230622,肇源县,2306 | |
| 719 | +230623,林甸县,2306 | |
| 720 | +230624,杜尔伯特蒙古族自治县,2306 | |
| 721 | +2307,伊春市,23 | |
| 722 | +230702,伊春区,2307 | |
| 723 | +230703,南岔区,2307 | |
| 724 | +230704,友好区,2307 | |
| 725 | +230705,西林区,2307 | |
| 726 | +230706,翠峦区,2307 | |
| 727 | +230707,新青区,2307 | |
| 728 | +230708,美溪区,2307 | |
| 729 | +230709,金山屯区,2307 | |
| 730 | +230710,五营区,2307 | |
| 731 | +230711,乌马河区,2307 | |
| 732 | +230712,汤旺河区,2307 | |
| 733 | +230713,带岭区,2307 | |
| 734 | +230714,乌伊岭区,2307 | |
| 735 | +230715,红星区,2307 | |
| 736 | +230716,上甘岭区,2307 | |
| 737 | +230722,嘉荫县,2307 | |
| 738 | +230781,铁力市,2307 | |
| 739 | +2308,佳木斯市,23 | |
| 740 | +230803,向阳区,2308 | |
| 741 | +230804,前进区,2308 | |
| 742 | +230805,东风区,2308 | |
| 743 | +230811,郊区,2308 | |
| 744 | +230822,桦南县,2308 | |
| 745 | +230826,桦川县,2308 | |
| 746 | +230828,汤原县,2308 | |
| 747 | +230881,同江市,2308 | |
| 748 | +230882,富锦市,2308 | |
| 749 | +230883,抚远市,2308 | |
| 750 | +2309,七台河市,23 | |
| 751 | +230902,新兴区,2309 | |
| 752 | +230903,桃山区,2309 | |
| 753 | +230904,茄子河区,2309 | |
| 754 | +230921,勃利县,2309 | |
| 755 | +2310,牡丹江市,23 | |
| 756 | +231002,东安区,2310 | |
| 757 | +231003,阳明区,2310 | |
| 758 | +231004,爱民区,2310 | |
| 759 | +231005,西安区,2310 | |
| 760 | +231025,林口县,2310 | |
| 761 | +231081,绥芬河市,2310 | |
| 762 | +231083,海林市,2310 | |
| 763 | +231084,宁安市,2310 | |
| 764 | +231085,穆棱市,2310 | |
| 765 | +231086,东宁市,2310 | |
| 766 | +2311,黑河市,23 | |
| 767 | +231102,爱辉区,2311 | |
| 768 | +231121,嫩江县,2311 | |
| 769 | +231123,逊克县,2311 | |
| 770 | +231124,孙吴县,2311 | |
| 771 | +231181,北安市,2311 | |
| 772 | +231182,五大连池市,2311 | |
| 773 | +2312,绥化市,23 | |
| 774 | +231202,北林区,2312 | |
| 775 | +231221,望奎县,2312 | |
| 776 | +231222,兰西县,2312 | |
| 777 | +231223,青冈县,2312 | |
| 778 | +231224,庆安县,2312 | |
| 779 | +231225,明水县,2312 | |
| 780 | +231226,绥棱县,2312 | |
| 781 | +231281,安达市,2312 | |
| 782 | +231282,肇东市,2312 | |
| 783 | +231283,海伦市,2312 | |
| 784 | +2327,大兴安岭地区,23 | |
| 785 | +232701,漠河市,2327 | |
| 786 | +232721,呼玛县,2327 | |
| 787 | +232722,塔河县,2327 | |
| 788 | +31,上海市, | |
| 789 | +310101,黄浦区,31 | |
| 790 | +310104,徐汇区,31 | |
| 791 | +310105,长宁区,31 | |
| 792 | +310106,静安区,31 | |
| 793 | +310107,普陀区,31 | |
| 794 | +310109,虹口区,31 | |
| 795 | +310110,杨浦区,31 | |
| 796 | +310112,闵行区,31 | |
| 797 | +310113,宝山区,31 | |
| 798 | +310114,嘉定区,31 | |
| 799 | +310115,浦东新区,31 | |
| 800 | +310116,金山区,31 | |
| 801 | +310117,松江区,31 | |
| 802 | +310118,青浦区,31 | |
| 803 | +310120,奉贤区,31 | |
| 804 | +310151,崇明区,31 | |
| 805 | +32,江苏省, | |
| 806 | +3201,南京市,32 | |
| 807 | +320102,玄武区,3201 | |
| 808 | +320104,秦淮区,3201 | |
| 809 | +320105,建邺区,3201 | |
| 810 | +320106,鼓楼区,3201 | |
| 811 | +320111,浦口区,3201 | |
| 812 | +320113,栖霞区,3201 | |
| 813 | +320114,雨花台区,3201 | |
| 814 | +320115,江宁区,3201 | |
| 815 | +320116,六合区,3201 | |
| 816 | +320117,溧水区,3201 | |
| 817 | +320118,高淳区,3201 | |
| 818 | +3202,无锡市,32 | |
| 819 | +320205,锡山区,3202 | |
| 820 | +320206,惠山区,3202 | |
| 821 | +320211,滨湖区,3202 | |
| 822 | +320213,梁溪区,3202 | |
| 823 | +320214,新吴区,3202 | |
| 824 | +320281,江阴市,3202 | |
| 825 | +320282,宜兴市,3202 | |
| 826 | +3203,徐州市,32 | |
| 827 | +320302,鼓楼区,3203 | |
| 828 | +320303,云龙区,3203 | |
| 829 | +320305,贾汪区,3203 | |
| 830 | +320311,泉山区,3203 | |
| 831 | +320312,铜山区,3203 | |
| 832 | +320321,丰县,3203 | |
| 833 | +320322,沛县,3203 | |
| 834 | +320324,睢宁县,3203 | |
| 835 | +320381,新沂市,3203 | |
| 836 | +320382,邳州市,3203 | |
| 837 | +3204,常州市,32 | |
| 838 | +320402,天宁区,3204 | |
| 839 | +320404,钟楼区,3204 | |
| 840 | +320411,新北区,3204 | |
| 841 | +320412,武进区,3204 | |
| 842 | +320413,金坛区,3204 | |
| 843 | +320481,溧阳市,3204 | |
| 844 | +3205,苏州市,32 | |
| 845 | +320505,虎丘区,3205 | |
| 846 | +320506,吴中区,3205 | |
| 847 | +320507,相城区,3205 | |
| 848 | +320508,姑苏区,3205 | |
| 849 | +320509,吴江区,3205 | |
| 850 | +320581,常熟市,3205 | |
| 851 | +320582,张家港市,3205 | |
| 852 | +320583,昆山市,3205 | |
| 853 | +320585,太仓市,3205 | |
| 854 | +3206,南通市,32 | |
| 855 | +320602,崇川区,3206 | |
| 856 | +320611,港闸区,3206 | |
| 857 | +320612,通州区,3206 | |
| 858 | +320623,如东县,3206 | |
| 859 | +320681,启东市,3206 | |
| 860 | +320682,如皋市,3206 | |
| 861 | +320684,海门市,3206 | |
| 862 | +320685,海安市,3206 | |
| 863 | +3207,连云港市,32 | |
| 864 | +320703,连云区,3207 | |
| 865 | +320706,海州区,3207 | |
| 866 | +320707,赣榆区,3207 | |
| 867 | +320722,东海县,3207 | |
| 868 | +320723,灌云县,3207 | |
| 869 | +320724,灌南县,3207 | |
| 870 | +3208,淮安市,32 | |
| 871 | +320803,淮安区,3208 | |
| 872 | +320804,淮阴区,3208 | |
| 873 | +320812,清江浦区,3208 | |
| 874 | +320813,洪泽区,3208 | |
| 875 | +320826,涟水县,3208 | |
| 876 | +320830,盱眙县,3208 | |
| 877 | +320831,金湖县,3208 | |
| 878 | +3209,盐城市,32 | |
| 879 | +320902,亭湖区,3209 | |
| 880 | +320903,盐都区,3209 | |
| 881 | +320904,大丰区,3209 | |
| 882 | +320921,响水县,3209 | |
| 883 | +320922,滨海县,3209 | |
| 884 | +320923,阜宁县,3209 | |
| 885 | +320924,射阳县,3209 | |
| 886 | +320925,建湖县,3209 | |
| 887 | +320981,东台市,3209 | |
| 888 | +3210,扬州市,32 | |
| 889 | +321002,广陵区,3210 | |
| 890 | +321003,邗江区,3210 | |
| 891 | +321012,江都区,3210 | |
| 892 | +321023,宝应县,3210 | |
| 893 | +321081,仪征市,3210 | |
| 894 | +321084,高邮市,3210 | |
| 895 | +3211,镇江市,32 | |
| 896 | +321102,京口区,3211 | |
| 897 | +321111,润州区,3211 | |
| 898 | +321112,丹徒区,3211 | |
| 899 | +321181,丹阳市,3211 | |
| 900 | +321182,扬中市,3211 | |
| 901 | +321183,句容市,3211 | |
| 902 | +3212,泰州市,32 | |
| 903 | +321202,海陵区,3212 | |
| 904 | +321203,高港区,3212 | |
| 905 | +321204,姜堰区,3212 | |
| 906 | +321281,兴化市,3212 | |
| 907 | +321282,靖江市,3212 | |
| 908 | +321283,泰兴市,3212 | |
| 909 | +3213,宿迁市,32 | |
| 910 | +321302,宿城区,3213 | |
| 911 | +321311,宿豫区,3213 | |
| 912 | +321322,沭阳县,3213 | |
| 913 | +321323,泗阳县,3213 | |
| 914 | +321324,泗洪县,3213 | |
| 915 | +33,浙江省, | |
| 916 | +3301,杭州市,33 | |
| 917 | +330102,上城区,3301 | |
| 918 | +330103,下城区,3301 | |
| 919 | +330104,江干区,3301 | |
| 920 | +330105,拱墅区,3301 | |
| 921 | +330106,西湖区,3301 | |
| 922 | +330108,滨江区,3301 | |
| 923 | +330109,萧山区,3301 | |
| 924 | +330110,余杭区,3301 | |
| 925 | +330111,富阳区,3301 | |
| 926 | +330112,临安区,3301 | |
| 927 | +330122,桐庐县,3301 | |
| 928 | +330127,淳安县,3301 | |
| 929 | +330182,建德市,3301 | |
| 930 | +3302,宁波市,33 | |
| 931 | +330203,海曙区,3302 | |
| 932 | +330205,江北区,3302 | |
| 933 | +330206,北仑区,3302 | |
| 934 | +330211,镇海区,3302 | |
| 935 | +330212,鄞州区,3302 | |
| 936 | +330213,奉化区,3302 | |
| 937 | +330225,象山县,3302 | |
| 938 | +330226,宁海县,3302 | |
| 939 | +330281,余姚市,3302 | |
| 940 | +330282,慈溪市,3302 | |
| 941 | +3303,温州市,33 | |
| 942 | +330302,鹿城区,3303 | |
| 943 | +330303,龙湾区,3303 | |
| 944 | +330304,瓯海区,3303 | |
| 945 | +330305,洞头区,3303 | |
| 946 | +330324,永嘉县,3303 | |
| 947 | +330326,平阳县,3303 | |
| 948 | +330327,苍南县,3303 | |
| 949 | +330328,文成县,3303 | |
| 950 | +330329,泰顺县,3303 | |
| 951 | +330381,瑞安市,3303 | |
| 952 | +330382,乐清市,3303 | |
| 953 | +3304,嘉兴市,33 | |
| 954 | +330402,南湖区,3304 | |
| 955 | +330411,秀洲区,3304 | |
| 956 | +330421,嘉善县,3304 | |
| 957 | +330424,海盐县,3304 | |
| 958 | +330481,海宁市,3304 | |
| 959 | +330482,平湖市,3304 | |
| 960 | +330483,桐乡市,3304 | |
| 961 | +3305,湖州市,33 | |
| 962 | +330502,吴兴区,3305 | |
| 963 | +330503,南浔区,3305 | |
| 964 | +330521,德清县,3305 | |
| 965 | +330522,长兴县,3305 | |
| 966 | +330523,安吉县,3305 | |
| 967 | +3306,绍兴市,33 | |
| 968 | +330602,越城区,3306 | |
| 969 | +330603,柯桥区,3306 | |
| 970 | +330604,上虞区,3306 | |
| 971 | +330624,新昌县,3306 | |
| 972 | +330681,诸暨市,3306 | |
| 973 | +330683,嵊州市,3306 | |
| 974 | +3307,金华市,33 | |
| 975 | +330702,婺城区,3307 | |
| 976 | +330703,金东区,3307 | |
| 977 | +330723,武义县,3307 | |
| 978 | +330726,浦江县,3307 | |
| 979 | +330727,磐安县,3307 | |
| 980 | +330781,兰溪市,3307 | |
| 981 | +330782,义乌市,3307 | |
| 982 | +330783,东阳市,3307 | |
| 983 | +330784,永康市,3307 | |
| 984 | +3308,衢州市,33 | |
| 985 | +330802,柯城区,3308 | |
| 986 | +330803,衢江区,3308 | |
| 987 | +330822,常山县,3308 | |
| 988 | +330824,开化县,3308 | |
| 989 | +330825,龙游县,3308 | |
| 990 | +330881,江山市,3308 | |
| 991 | +3309,舟山市,33 | |
| 992 | +330902,定海区,3309 | |
| 993 | +330903,普陀区,3309 | |
| 994 | +330921,岱山县,3309 | |
| 995 | +330922,嵊泗县,3309 | |
| 996 | +3310,台州市,33 | |
| 997 | +331002,椒江区,3310 | |
| 998 | +331003,黄岩区,3310 | |
| 999 | +331004,路桥区,3310 | |
| 1000 | +331022,三门县,3310 | |
| 1001 | +331023,天台县,3310 | |
| 1002 | +331024,仙居县,3310 | |
| 1003 | +331081,温岭市,3310 | |
| 1004 | +331082,临海市,3310 | |
| 1005 | +331083,玉环市,3310 | |
| 1006 | +3311,丽水市,33 | |
| 1007 | +331102,莲都区,3311 | |
| 1008 | +331121,青田县,3311 | |
| 1009 | +331122,缙云县,3311 | |
| 1010 | +331123,遂昌县,3311 | |
| 1011 | +331124,松阳县,3311 | |
| 1012 | +331125,云和县,3311 | |
| 1013 | +331126,庆元县,3311 | |
| 1014 | +331127,景宁畲族自治县,3311 | |
| 1015 | +331181,龙泉市,3311 | |
| 1016 | +34,安徽省, | |
| 1017 | +3401,合肥市,34 | |
| 1018 | +340102,瑶海区,3401 | |
| 1019 | +340103,庐阳区,3401 | |
| 1020 | +340104,蜀山区,3401 | |
| 1021 | +340111,包河区,3401 | |
| 1022 | +340121,长丰县,3401 | |
| 1023 | +340122,肥东县,3401 | |
| 1024 | +340123,肥西县,3401 | |
| 1025 | +340124,庐江县,3401 | |
| 1026 | +340181,巢湖市,3401 | |
| 1027 | +3402,芜湖市,34 | |
| 1028 | +340202,镜湖区,3402 | |
| 1029 | +340203,弋江区,3402 | |
| 1030 | +340207,鸠江区,3402 | |
| 1031 | +340208,三山区,3402 | |
| 1032 | +340221,芜湖县,3402 | |
| 1033 | +340222,繁昌县,3402 | |
| 1034 | +340223,南陵县,3402 | |
| 1035 | +340225,无为县,3402 | |
| 1036 | +3403,蚌埠市,34 | |
| 1037 | +340302,龙子湖区,3403 | |
| 1038 | +340303,蚌山区,3403 | |
| 1039 | +340304,禹会区,3403 | |
| 1040 | +340311,淮上区,3403 | |
| 1041 | +340321,怀远县,3403 | |
| 1042 | +340322,五河县,3403 | |
| 1043 | +340323,固镇县,3403 | |
| 1044 | +3404,淮南市,34 | |
| 1045 | +340402,大通区,3404 | |
| 1046 | +340403,田家庵区,3404 | |
| 1047 | +340404,谢家集区,3404 | |
| 1048 | +340405,八公山区,3404 | |
| 1049 | +340406,潘集区,3404 | |
| 1050 | +340421,凤台县,3404 | |
| 1051 | +340422,寿县,3404 | |
| 1052 | +3405,马鞍山市,34 | |
| 1053 | +340503,花山区,3405 | |
| 1054 | +340504,雨山区,3405 | |
| 1055 | +340506,博望区,3405 | |
| 1056 | +340521,当涂县,3405 | |
| 1057 | +340522,含山县,3405 | |
| 1058 | +340523,和县,3405 | |
| 1059 | +3406,淮北市,34 | |
| 1060 | +340602,杜集区,3406 | |
| 1061 | +340603,相山区,3406 | |
| 1062 | +340604,烈山区,3406 | |
| 1063 | +340621,濉溪县,3406 | |
| 1064 | +3407,铜陵市,34 | |
| 1065 | +340705,铜官区,3407 | |
| 1066 | +340706,义安区,3407 | |
| 1067 | +340711,郊区,3407 | |
| 1068 | +340722,枞阳县,3407 | |
| 1069 | +3408,安庆市,34 | |
| 1070 | +340802,迎江区,3408 | |
| 1071 | +340803,大观区,3408 | |
| 1072 | +340811,宜秀区,3408 | |
| 1073 | +340822,怀宁县,3408 | |
| 1074 | +340825,太湖县,3408 | |
| 1075 | +340826,宿松县,3408 | |
| 1076 | +340827,望江县,3408 | |
| 1077 | +340828,岳西县,3408 | |
| 1078 | +340881,桐城市,3408 | |
| 1079 | +340882,潜山市,3408 | |
| 1080 | +3410,黄山市,34 | |
| 1081 | +341002,屯溪区,3410 | |
| 1082 | +341003,黄山区,3410 | |
| 1083 | +341004,徽州区,3410 | |
| 1084 | +341021,歙县,3410 | |
| 1085 | +341022,休宁县,3410 | |
| 1086 | +341023,黟县,3410 | |
| 1087 | +341024,祁门县,3410 | |
| 1088 | +3411,滁州市,34 | |
| 1089 | +341102,琅琊区,3411 | |
| 1090 | +341103,南谯区,3411 | |
| 1091 | +341122,来安县,3411 | |
| 1092 | +341124,全椒县,3411 | |
| 1093 | +341125,定远县,3411 | |
| 1094 | +341126,凤阳县,3411 | |
| 1095 | +341181,天长市,3411 | |
| 1096 | +341182,明光市,3411 | |
| 1097 | +3412,阜阳市,34 | |
| 1098 | +341202,颍州区,3412 | |
| 1099 | +341203,颍东区,3412 | |
| 1100 | +341204,颍泉区,3412 | |
| 1101 | +341221,临泉县,3412 | |
| 1102 | +341222,太和县,3412 | |
| 1103 | +341225,阜南县,3412 | |
| 1104 | +341226,颍上县,3412 | |
| 1105 | +341282,界首市,3412 | |
| 1106 | +3413,宿州市,34 | |
| 1107 | +341302,埇桥区,3413 | |
| 1108 | +341321,砀山县,3413 | |
| 1109 | +341322,萧县,3413 | |
| 1110 | +341323,灵璧县,3413 | |
| 1111 | +341324,泗县,3413 | |
| 1112 | +3415,六安市,34 | |
| 1113 | +341502,金安区,3415 | |
| 1114 | +341503,裕安区,3415 | |
| 1115 | +341504,叶集区,3415 | |
| 1116 | +341522,霍邱县,3415 | |
| 1117 | +341523,舒城县,3415 | |
| 1118 | +341524,金寨县,3415 | |
| 1119 | +341525,霍山县,3415 | |
| 1120 | +3416,亳州市,34 | |
| 1121 | +341602,谯城区,3416 | |
| 1122 | +341621,涡阳县,3416 | |
| 1123 | +341622,蒙城县,3416 | |
| 1124 | +341623,利辛县,3416 | |
| 1125 | +3417,池州市,34 | |
| 1126 | +341702,贵池区,3417 | |
| 1127 | +341721,东至县,3417 | |
| 1128 | +341722,石台县,3417 | |
| 1129 | +341723,青阳县,3417 | |
| 1130 | +3418,宣城市,34 | |
| 1131 | +341802,宣州区,3418 | |
| 1132 | +341821,郎溪县,3418 | |
| 1133 | +341822,广德县,3418 | |
| 1134 | +341823,泾县,3418 | |
| 1135 | +341824,绩溪县,3418 | |
| 1136 | +341825,旌德县,3418 | |
| 1137 | +341881,宁国市,3418 | |
| 1138 | +35,福建省, | |
| 1139 | +3501,福州市,35 | |
| 1140 | +350102,鼓楼区,3501 | |
| 1141 | +350103,台江区,3501 | |
| 1142 | +350104,仓山区,3501 | |
| 1143 | +350105,马尾区,3501 | |
| 1144 | +350111,晋安区,3501 | |
| 1145 | +350112,长乐区,3501 | |
| 1146 | +350121,闽侯县,3501 | |
| 1147 | +350122,连江县,3501 | |
| 1148 | +350123,罗源县,3501 | |
| 1149 | +350124,闽清县,3501 | |
| 1150 | +350125,永泰县,3501 | |
| 1151 | +350128,平潭县,3501 | |
| 1152 | +350181,福清市,3501 | |
| 1153 | +3502,厦门市,35 | |
| 1154 | +350203,思明区,3502 | |
| 1155 | +350205,海沧区,3502 | |
| 1156 | +350206,湖里区,3502 | |
| 1157 | +350211,集美区,3502 | |
| 1158 | +350212,同安区,3502 | |
| 1159 | +350213,翔安区,3502 | |
| 1160 | +3503,莆田市,35 | |
| 1161 | +350302,城厢区,3503 | |
| 1162 | +350303,涵江区,3503 | |
| 1163 | +350304,荔城区,3503 | |
| 1164 | +350305,秀屿区,3503 | |
| 1165 | +350322,仙游县,3503 | |
| 1166 | +3504,三明市,35 | |
| 1167 | +350402,梅列区,3504 | |
| 1168 | +350403,三元区,3504 | |
| 1169 | +350421,明溪县,3504 | |
| 1170 | +350423,清流县,3504 | |
| 1171 | +350424,宁化县,3504 | |
| 1172 | +350425,大田县,3504 | |
| 1173 | +350426,尤溪县,3504 | |
| 1174 | +350427,沙县,3504 | |
| 1175 | +350428,将乐县,3504 | |
| 1176 | +350429,泰宁县,3504 | |
| 1177 | +350430,建宁县,3504 | |
| 1178 | +350481,永安市,3504 | |
| 1179 | +3505,泉州市,35 | |
| 1180 | +350502,鲤城区,3505 | |
| 1181 | +350503,丰泽区,3505 | |
| 1182 | +350504,洛江区,3505 | |
| 1183 | +350505,泉港区,3505 | |
| 1184 | +350521,惠安县,3505 | |
| 1185 | +350524,安溪县,3505 | |
| 1186 | +350525,永春县,3505 | |
| 1187 | +350526,德化县,3505 | |
| 1188 | +350527,金门县,3505 | |
| 1189 | +350581,石狮市,3505 | |
| 1190 | +350582,晋江市,3505 | |
| 1191 | +350583,南安市,3505 | |
| 1192 | +3506,漳州市,35 | |
| 1193 | +350602,芗城区,3506 | |
| 1194 | +350603,龙文区,3506 | |
| 1195 | +350622,云霄县,3506 | |
| 1196 | +350623,漳浦县,3506 | |
| 1197 | +350624,诏安县,3506 | |
| 1198 | +350625,长泰县,3506 | |
| 1199 | +350626,东山县,3506 | |
| 1200 | +350627,南靖县,3506 | |
| 1201 | +350628,平和县,3506 | |
| 1202 | +350629,华安县,3506 | |
| 1203 | +350681,龙海市,3506 | |
| 1204 | +3507,南平市,35 | |
| 1205 | +350702,延平区,3507 | |
| 1206 | +350703,建阳区,3507 | |
| 1207 | +350721,顺昌县,3507 | |
| 1208 | +350722,浦城县,3507 | |
| 1209 | +350723,光泽县,3507 | |
| 1210 | +350724,松溪县,3507 | |
| 1211 | +350725,政和县,3507 | |
| 1212 | +350781,邵武市,3507 | |
| 1213 | +350782,武夷山市,3507 | |
| 1214 | +350783,建瓯市,3507 | |
| 1215 | +3508,龙岩市,35 | |
| 1216 | +350802,新罗区,3508 | |
| 1217 | +350803,永定区,3508 | |
| 1218 | +350821,长汀县,3508 | |
| 1219 | +350823,上杭县,3508 | |
| 1220 | +350824,武平县,3508 | |
| 1221 | +350825,连城县,3508 | |
| 1222 | +350881,漳平市,3508 | |
| 1223 | +3509,宁德市,35 | |
| 1224 | +350902,蕉城区,3509 | |
| 1225 | +350921,霞浦县,3509 | |
| 1226 | +350922,古田县,3509 | |
| 1227 | +350923,屏南县,3509 | |
| 1228 | +350924,寿宁县,3509 | |
| 1229 | +350925,周宁县,3509 | |
| 1230 | +350926,柘荣县,3509 | |
| 1231 | +350981,福安市,3509 | |
| 1232 | +350982,福鼎市,3509 | |
| 1233 | +36,江西省, | |
| 1234 | +3601,南昌市,36 | |
| 1235 | +360102,东湖区,3601 | |
| 1236 | +360103,西湖区,3601 | |
| 1237 | +360104,青云谱区,3601 | |
| 1238 | +360105,湾里区,3601 | |
| 1239 | +360111,青山湖区,3601 | |
| 1240 | +360112,新建区,3601 | |
| 1241 | +360121,南昌县,3601 | |
| 1242 | +360123,安义县,3601 | |
| 1243 | +360124,进贤县,3601 | |
| 1244 | +3602,景德镇市,36 | |
| 1245 | +360202,昌江区,3602 | |
| 1246 | +360203,珠山区,3602 | |
| 1247 | +360222,浮梁县,3602 | |
| 1248 | +360281,乐平市,3602 | |
| 1249 | +3603,萍乡市,36 | |
| 1250 | +360302,安源区,3603 | |
| 1251 | +360313,湘东区,3603 | |
| 1252 | +360321,莲花县,3603 | |
| 1253 | +360322,上栗县,3603 | |
| 1254 | +360323,芦溪县,3603 | |
| 1255 | +3604,九江市,36 | |
| 1256 | +360402,濂溪区,3604 | |
| 1257 | +360403,浔阳区,3604 | |
| 1258 | +360404,柴桑区,3604 | |
| 1259 | +360423,武宁县,3604 | |
| 1260 | +360424,修水县,3604 | |
| 1261 | +360425,永修县,3604 | |
| 1262 | +360426,德安县,3604 | |
| 1263 | +360428,都昌县,3604 | |
| 1264 | +360429,湖口县,3604 | |
| 1265 | +360430,彭泽县,3604 | |
| 1266 | +360481,瑞昌市,3604 | |
| 1267 | +360482,共青城市,3604 | |
| 1268 | +360483,庐山市,3604 | |
| 1269 | +3605,新余市,36 | |
| 1270 | +360502,渝水区,3605 | |
| 1271 | +360521,分宜县,3605 | |
| 1272 | +3606,鹰潭市,36 | |
| 1273 | +360602,月湖区,3606 | |
| 1274 | +360603,余江区,3606 | |
| 1275 | +360681,贵溪市,3606 | |
| 1276 | +3607,赣州市,36 | |
| 1277 | +360702,章贡区,3607 | |
| 1278 | +360703,南康区,3607 | |
| 1279 | +360704,赣县区,3607 | |
| 1280 | +360722,信丰县,3607 | |
| 1281 | +360723,大余县,3607 | |
| 1282 | +360724,上犹县,3607 | |
| 1283 | +360725,崇义县,3607 | |
| 1284 | +360726,安远县,3607 | |
| 1285 | +360727,龙南县,3607 | |
| 1286 | +360728,定南县,3607 | |
| 1287 | +360729,全南县,3607 | |
| 1288 | +360730,宁都县,3607 | |
| 1289 | +360731,于都县,3607 | |
| 1290 | +360732,兴国县,3607 | |
| 1291 | +360733,会昌县,3607 | |
| 1292 | +360734,寻乌县,3607 | |
| 1293 | +360735,石城县,3607 | |
| 1294 | +360781,瑞金市,3607 | |
| 1295 | +3608,吉安市,36 | |
| 1296 | +360802,吉州区,3608 | |
| 1297 | +360803,青原区,3608 | |
| 1298 | +360821,吉安县,3608 | |
| 1299 | +360822,吉水县,3608 | |
| 1300 | +360823,峡江县,3608 | |
| 1301 | +360824,新干县,3608 | |
| 1302 | +360825,永丰县,3608 | |
| 1303 | +360826,泰和县,3608 | |
| 1304 | +360827,遂川县,3608 | |
| 1305 | +360828,万安县,3608 | |
| 1306 | +360829,安福县,3608 | |
| 1307 | +360830,永新县,3608 | |
| 1308 | +360881,井冈山市,3608 | |
| 1309 | +3609,宜春市,36 | |
| 1310 | +360902,袁州区,3609 | |
| 1311 | +360921,奉新县,3609 | |
| 1312 | +360922,万载县,3609 | |
| 1313 | +360923,上高县,3609 | |
| 1314 | +360924,宜丰县,3609 | |
| 1315 | +360925,靖安县,3609 | |
| 1316 | +360926,铜鼓县,3609 | |
| 1317 | +360981,丰城市,3609 | |
| 1318 | +360982,樟树市,3609 | |
| 1319 | +360983,高安市,3609 | |
| 1320 | +3610,抚州市,36 | |
| 1321 | +361002,临川区,3610 | |
| 1322 | +361003,东乡区,3610 | |
| 1323 | +361021,南城县,3610 | |
| 1324 | +361022,黎川县,3610 | |
| 1325 | +361023,南丰县,3610 | |
| 1326 | +361024,崇仁县,3610 | |
| 1327 | +361025,乐安县,3610 | |
| 1328 | +361026,宜黄县,3610 | |
| 1329 | +361027,金溪县,3610 | |
| 1330 | +361028,资溪县,3610 | |
| 1331 | +361030,广昌县,3610 | |
| 1332 | +3611,上饶市,36 | |
| 1333 | +361102,信州区,3611 | |
| 1334 | +361103,广丰区,3611 | |
| 1335 | +361121,上饶县,3611 | |
| 1336 | +361123,玉山县,3611 | |
| 1337 | +361124,铅山县,3611 | |
| 1338 | +361125,横峰县,3611 | |
| 1339 | +361126,弋阳县,3611 | |
| 1340 | +361127,余干县,3611 | |
| 1341 | +361128,鄱阳县,3611 | |
| 1342 | +361129,万年县,3611 | |
| 1343 | +361130,婺源县,3611 | |
| 1344 | +361181,德兴市,3611 | |
| 1345 | +37,山东省, | |
| 1346 | +3701,济南市,37 | |
| 1347 | +370102,历下区,3701 | |
| 1348 | +370103,市中区,3701 | |
| 1349 | +370104,槐荫区,3701 | |
| 1350 | +370105,天桥区,3701 | |
| 1351 | +370112,历城区,3701 | |
| 1352 | +370113,长清区,3701 | |
| 1353 | +370114,章丘区,3701 | |
| 1354 | +370115,济阳区,3701 | |
| 1355 | +370124,平阴县,3701 | |
| 1356 | +370126,商河县,3701 | |
| 1357 | +3702,青岛市,37 | |
| 1358 | +370202,市南区,3702 | |
| 1359 | +370203,市北区,3702 | |
| 1360 | +370211,黄岛区,3702 | |
| 1361 | +370212,崂山区,3702 | |
| 1362 | +370213,李沧区,3702 | |
| 1363 | +370214,城阳区,3702 | |
| 1364 | +370215,即墨区,3702 | |
| 1365 | +370281,胶州市,3702 | |
| 1366 | +370283,平度市,3702 | |
| 1367 | +370285,莱西市,3702 | |
| 1368 | +3703,淄博市,37 | |
| 1369 | +370302,淄川区,3703 | |
| 1370 | +370303,张店区,3703 | |
| 1371 | +370304,博山区,3703 | |
| 1372 | +370305,临淄区,3703 | |
| 1373 | +370306,周村区,3703 | |
| 1374 | +370321,桓台县,3703 | |
| 1375 | +370322,高青县,3703 | |
| 1376 | +370323,沂源县,3703 | |
| 1377 | +3704,枣庄市,37 | |
| 1378 | +370402,市中区,3704 | |
| 1379 | +370403,薛城区,3704 | |
| 1380 | +370404,峄城区,3704 | |
| 1381 | +370405,台儿庄区,3704 | |
| 1382 | +370406,山亭区,3704 | |
| 1383 | +370481,滕州市,3704 | |
| 1384 | +3705,东营市,37 | |
| 1385 | +370502,东营区,3705 | |
| 1386 | +370503,河口区,3705 | |
| 1387 | +370505,垦利区,3705 | |
| 1388 | +370522,利津县,3705 | |
| 1389 | +370523,广饶县,3705 | |
| 1390 | +3706,烟台市,37 | |
| 1391 | +370602,芝罘区,3706 | |
| 1392 | +370611,福山区,3706 | |
| 1393 | +370612,牟平区,3706 | |
| 1394 | +370613,莱山区,3706 | |
| 1395 | +370634,长岛县,3706 | |
| 1396 | +370681,龙口市,3706 | |
| 1397 | +370682,莱阳市,3706 | |
| 1398 | +370683,莱州市,3706 | |
| 1399 | +370684,蓬莱市,3706 | |
| 1400 | +370685,招远市,3706 | |
| 1401 | +370686,栖霞市,3706 | |
| 1402 | +370687,海阳市,3706 | |
| 1403 | +3707,潍坊市,37 | |
| 1404 | +370702,潍城区,3707 | |
| 1405 | +370703,寒亭区,3707 | |
| 1406 | +370704,坊子区,3707 | |
| 1407 | +370705,奎文区,3707 | |
| 1408 | +370724,临朐县,3707 | |
| 1409 | +370725,昌乐县,3707 | |
| 1410 | +370781,青州市,3707 | |
| 1411 | +370782,诸城市,3707 | |
| 1412 | +370783,寿光市,3707 | |
| 1413 | +370784,安丘市,3707 | |
| 1414 | +370785,高密市,3707 | |
| 1415 | +370786,昌邑市,3707 | |
| 1416 | +3708,济宁市,37 | |
| 1417 | +370811,任城区,3708 | |
| 1418 | +370812,兖州区,3708 | |
| 1419 | +370826,微山县,3708 | |
| 1420 | +370827,鱼台县,3708 | |
| 1421 | +370828,金乡县,3708 | |
| 1422 | +370829,嘉祥县,3708 | |
| 1423 | +370830,汶上县,3708 | |
| 1424 | +370831,泗水县,3708 | |
| 1425 | +370832,梁山县,3708 | |
| 1426 | +370881,曲阜市,3708 | |
| 1427 | +370883,邹城市,3708 | |
| 1428 | +3709,泰安市,37 | |
| 1429 | +370902,泰山区,3709 | |
| 1430 | +370911,岱岳区,3709 | |
| 1431 | +370921,宁阳县,3709 | |
| 1432 | +370923,东平县,3709 | |
| 1433 | +370982,新泰市,3709 | |
| 1434 | +370983,肥城市,3709 | |
| 1435 | +3710,威海市,37 | |
| 1436 | +371002,环翠区,3710 | |
| 1437 | +371003,文登区,3710 | |
| 1438 | +371082,荣成市,3710 | |
| 1439 | +371083,乳山市,3710 | |
| 1440 | +3711,日照市,37 | |
| 1441 | +371102,东港区,3711 | |
| 1442 | +371103,岚山区,3711 | |
| 1443 | +371121,五莲县,3711 | |
| 1444 | +371122,莒县,3711 | |
| 1445 | +3712,莱芜市,37 | |
| 1446 | +371202,莱城区,3712 | |
| 1447 | +371203,钢城区,3712 | |
| 1448 | +3713,临沂市,37 | |
| 1449 | +371302,兰山区,3713 | |
| 1450 | +371311,罗庄区,3713 | |
| 1451 | +371312,河东区,3713 | |
| 1452 | +371321,沂南县,3713 | |
| 1453 | +371322,郯城县,3713 | |
| 1454 | +371323,沂水县,3713 | |
| 1455 | +371324,兰陵县,3713 | |
| 1456 | +371325,费县,3713 | |
| 1457 | +371326,平邑县,3713 | |
| 1458 | +371327,莒南县,3713 | |
| 1459 | +371328,蒙阴县,3713 | |
| 1460 | +371329,临沭县,3713 | |
| 1461 | +3714,德州市,37 | |
| 1462 | +371402,德城区,3714 | |
| 1463 | +371403,陵城区,3714 | |
| 1464 | +371422,宁津县,3714 | |
| 1465 | +371423,庆云县,3714 | |
| 1466 | +371424,临邑县,3714 | |
| 1467 | +371425,齐河县,3714 | |
| 1468 | +371426,平原县,3714 | |
| 1469 | +371427,夏津县,3714 | |
| 1470 | +371428,武城县,3714 | |
| 1471 | +371481,乐陵市,3714 | |
| 1472 | +371482,禹城市,3714 | |
| 1473 | +3715,聊城市,37 | |
| 1474 | +371502,东昌府区,3715 | |
| 1475 | +371521,阳谷县,3715 | |
| 1476 | +371522,莘县,3715 | |
| 1477 | +371523,茌平县,3715 | |
| 1478 | +371524,东阿县,3715 | |
| 1479 | +371525,冠县,3715 | |
| 1480 | +371526,高唐县,3715 | |
| 1481 | +371581,临清市,3715 | |
| 1482 | +3716,滨州市,37 | |
| 1483 | +371602,滨城区,3716 | |
| 1484 | +371603,沾化区,3716 | |
| 1485 | +371621,惠民县,3716 | |
| 1486 | +371622,阳信县,3716 | |
| 1487 | +371623,无棣县,3716 | |
| 1488 | +371625,博兴县,3716 | |
| 1489 | +371681,邹平市,3716 | |
| 1490 | +3717,菏泽市,37 | |
| 1491 | +371702,牡丹区,3717 | |
| 1492 | +371703,定陶区,3717 | |
| 1493 | +371721,曹县,3717 | |
| 1494 | +371722,单县,3717 | |
| 1495 | +371723,成武县,3717 | |
| 1496 | +371724,巨野县,3717 | |
| 1497 | +371725,郓城县,3717 | |
| 1498 | +371726,鄄城县,3717 | |
| 1499 | +371728,东明县,3717 | |
| 1500 | +41,河南省, | |
| 1501 | +4101,郑州市,41 | |
| 1502 | +410102,中原区,4101 | |
| 1503 | +410103,二七区,4101 | |
| 1504 | +410104,管城回族区,4101 | |
| 1505 | +410105,金水区,4101 | |
| 1506 | +410106,上街区,4101 | |
| 1507 | +410108,惠济区,4101 | |
| 1508 | +410122,中牟县,4101 | |
| 1509 | +410181,巩义市,4101 | |
| 1510 | +410182,荥阳市,4101 | |
| 1511 | +410183,新密市,4101 | |
| 1512 | +410184,新郑市,4101 | |
| 1513 | +410185,登封市,4101 | |
| 1514 | +4102,开封市,41 | |
| 1515 | +410202,龙亭区,4102 | |
| 1516 | +410203,顺河回族区,4102 | |
| 1517 | +410204,鼓楼区,4102 | |
| 1518 | +410205,禹王台区,4102 | |
| 1519 | +410212,祥符区,4102 | |
| 1520 | +410221,杞县,4102 | |
| 1521 | +410222,通许县,4102 | |
| 1522 | +410223,尉氏县,4102 | |
| 1523 | +410225,兰考县,4102 | |
| 1524 | +4103,洛阳市,41 | |
| 1525 | +410302,老城区,4103 | |
| 1526 | +410303,西工区,4103 | |
| 1527 | +410304,瀍河回族区,4103 | |
| 1528 | +410305,涧西区,4103 | |
| 1529 | +410306,吉利区,4103 | |
| 1530 | +410311,洛龙区,4103 | |
| 1531 | +410322,孟津县,4103 | |
| 1532 | +410323,新安县,4103 | |
| 1533 | +410324,栾川县,4103 | |
| 1534 | +410325,嵩县,4103 | |
| 1535 | +410326,汝阳县,4103 | |
| 1536 | +410327,宜阳县,4103 | |
| 1537 | +410328,洛宁县,4103 | |
| 1538 | +410329,伊川县,4103 | |
| 1539 | +410381,偃师市,4103 | |
| 1540 | +4104,平顶山市,41 | |
| 1541 | +410402,新华区,4104 | |
| 1542 | +410403,卫东区,4104 | |
| 1543 | +410404,石龙区,4104 | |
| 1544 | +410411,湛河区,4104 | |
| 1545 | +410421,宝丰县,4104 | |
| 1546 | +410422,叶县,4104 | |
| 1547 | +410423,鲁山县,4104 | |
| 1548 | +410425,郏县,4104 | |
| 1549 | +410481,舞钢市,4104 | |
| 1550 | +410482,汝州市,4104 | |
| 1551 | +4105,安阳市,41 | |
| 1552 | +410502,文峰区,4105 | |
| 1553 | +410503,北关区,4105 | |
| 1554 | +410505,殷都区,4105 | |
| 1555 | +410506,龙安区,4105 | |
| 1556 | +410522,安阳县,4105 | |
| 1557 | +410523,汤阴县,4105 | |
| 1558 | +410526,滑县,4105 | |
| 1559 | +410527,内黄县,4105 | |
| 1560 | +410581,林州市,4105 | |
| 1561 | +4106,鹤壁市,41 | |
| 1562 | +410602,鹤山区,4106 | |
| 1563 | +410603,山城区,4106 | |
| 1564 | +410611,淇滨区,4106 | |
| 1565 | +410621,浚县,4106 | |
| 1566 | +410622,淇县,4106 | |
| 1567 | +4107,新乡市,41 | |
| 1568 | +410702,红旗区,4107 | |
| 1569 | +410703,卫滨区,4107 | |
| 1570 | +410704,凤泉区,4107 | |
| 1571 | +410711,牧野区,4107 | |
| 1572 | +410721,新乡县,4107 | |
| 1573 | +410724,获嘉县,4107 | |
| 1574 | +410725,原阳县,4107 | |
| 1575 | +410726,延津县,4107 | |
| 1576 | +410727,封丘县,4107 | |
| 1577 | +410728,长垣县,4107 | |
| 1578 | +410781,卫辉市,4107 | |
| 1579 | +410782,辉县市,4107 | |
| 1580 | +4108,焦作市,41 | |
| 1581 | +410802,解放区,4108 | |
| 1582 | +410803,中站区,4108 | |
| 1583 | +410804,马村区,4108 | |
| 1584 | +410811,山阳区,4108 | |
| 1585 | +410821,修武县,4108 | |
| 1586 | +410822,博爱县,4108 | |
| 1587 | +410823,武陟县,4108 | |
| 1588 | +410825,温县,4108 | |
| 1589 | +410882,沁阳市,4108 | |
| 1590 | +410883,孟州市,4108 | |
| 1591 | +4109,濮阳市,41 | |
| 1592 | +410902,华龙区,4109 | |
| 1593 | +410922,清丰县,4109 | |
| 1594 | +410923,南乐县,4109 | |
| 1595 | +410926,范县,4109 | |
| 1596 | +410927,台前县,4109 | |
| 1597 | +410928,濮阳县,4109 | |
| 1598 | +4110,许昌市,41 | |
| 1599 | +411002,魏都区,4110 | |
| 1600 | +411003,建安区,4110 | |
| 1601 | +411024,鄢陵县,4110 | |
| 1602 | +411025,襄城县,4110 | |
| 1603 | +411081,禹州市,4110 | |
| 1604 | +411082,长葛市,4110 | |
| 1605 | +4111,漯河市,41 | |
| 1606 | +411102,源汇区,4111 | |
| 1607 | +411103,郾城区,4111 | |
| 1608 | +411104,召陵区,4111 | |
| 1609 | +411121,舞阳县,4111 | |
| 1610 | +411122,临颍县,4111 | |
| 1611 | +4112,三门峡市,41 | |
| 1612 | +411202,湖滨区,4112 | |
| 1613 | +411203,陕州区,4112 | |
| 1614 | +411221,渑池县,4112 | |
| 1615 | +411224,卢氏县,4112 | |
| 1616 | +411281,义马市,4112 | |
| 1617 | +411282,灵宝市,4112 | |
| 1618 | +4113,南阳市,41 | |
| 1619 | +411302,宛城区,4113 | |
| 1620 | +411303,卧龙区,4113 | |
| 1621 | +411321,南召县,4113 | |
| 1622 | +411322,方城县,4113 | |
| 1623 | +411323,西峡县,4113 | |
| 1624 | +411324,镇平县,4113 | |
| 1625 | +411325,内乡县,4113 | |
| 1626 | +411326,淅川县,4113 | |
| 1627 | +411327,社旗县,4113 | |
| 1628 | +411328,唐河县,4113 | |
| 1629 | +411329,新野县,4113 | |
| 1630 | +411330,桐柏县,4113 | |
| 1631 | +411381,邓州市,4113 | |
| 1632 | +4114,商丘市,41 | |
| 1633 | +411402,梁园区,4114 | |
| 1634 | +411403,睢阳区,4114 | |
| 1635 | +411421,民权县,4114 | |
| 1636 | +411422,睢县,4114 | |
| 1637 | +411423,宁陵县,4114 | |
| 1638 | +411424,柘城县,4114 | |
| 1639 | +411425,虞城县,4114 | |
| 1640 | +411426,夏邑县,4114 | |
| 1641 | +411481,永城市,4114 | |
| 1642 | +4115,信阳市,41 | |
| 1643 | +411502,浉河区,4115 | |
| 1644 | +411503,平桥区,4115 | |
| 1645 | +411521,罗山县,4115 | |
| 1646 | +411522,光山县,4115 | |
| 1647 | +411523,新县,4115 | |
| 1648 | +411524,商城县,4115 | |
| 1649 | +411525,固始县,4115 | |
| 1650 | +411526,潢川县,4115 | |
| 1651 | +411527,淮滨县,4115 | |
| 1652 | +411528,息县,4115 | |
| 1653 | +4116,周口市,41 | |
| 1654 | +411602,川汇区,4116 | |
| 1655 | +411621,扶沟县,4116 | |
| 1656 | +411622,西华县,4116 | |
| 1657 | +411623,商水县,4116 | |
| 1658 | +411624,沈丘县,4116 | |
| 1659 | +411625,郸城县,4116 | |
| 1660 | +411626,淮阳县,4116 | |
| 1661 | +411627,太康县,4116 | |
| 1662 | +411628,鹿邑县,4116 | |
| 1663 | +411681,项城市,4116 | |
| 1664 | +4117,驻马店市,41 | |
| 1665 | +411702,驿城区,4117 | |
| 1666 | +411721,西平县,4117 | |
| 1667 | +411722,上蔡县,4117 | |
| 1668 | +411723,平舆县,4117 | |
| 1669 | +411724,正阳县,4117 | |
| 1670 | +411725,确山县,4117 | |
| 1671 | +411726,泌阳县,4117 | |
| 1672 | +411727,汝南县,4117 | |
| 1673 | +411728,遂平县,4117 | |
| 1674 | +411729,新蔡县,4117 | |
| 1675 | +419001,济源市,41 | |
| 1676 | +42,湖北省, | |
| 1677 | +4201,武汉市,42 | |
| 1678 | +420102,江岸区,4201 | |
| 1679 | +420103,江汉区,4201 | |
| 1680 | +420104,硚口区,4201 | |
| 1681 | +420105,汉阳区,4201 | |
| 1682 | +420106,武昌区,4201 | |
| 1683 | +420107,青山区,4201 | |
| 1684 | +420111,洪山区,4201 | |
| 1685 | +420112,东西湖区,4201 | |
| 1686 | +420113,汉南区,4201 | |
| 1687 | +420114,蔡甸区,4201 | |
| 1688 | +420115,江夏区,4201 | |
| 1689 | +420116,黄陂区,4201 | |
| 1690 | +420117,新洲区,4201 | |
| 1691 | +4202,黄石市,42 | |
| 1692 | +420202,黄石港区,4202 | |
| 1693 | +420203,西塞山区,4202 | |
| 1694 | +420204,下陆区,4202 | |
| 1695 | +420205,铁山区,4202 | |
| 1696 | +420222,阳新县,4202 | |
| 1697 | +420281,大冶市,4202 | |
| 1698 | +4203,十堰市,42 | |
| 1699 | +420302,茅箭区,4203 | |
| 1700 | +420303,张湾区,4203 | |
| 1701 | +420304,郧阳区,4203 | |
| 1702 | +420322,郧西县,4203 | |
| 1703 | +420323,竹山县,4203 | |
| 1704 | +420324,竹溪县,4203 | |
| 1705 | +420325,房县,4203 | |
| 1706 | +420381,丹江口市,4203 | |
| 1707 | +4205,宜昌市,42 | |
| 1708 | +420502,西陵区,4205 | |
| 1709 | +420503,伍家岗区,4205 | |
| 1710 | +420504,点军区,4205 | |
| 1711 | +420505,猇亭区,4205 | |
| 1712 | +420506,夷陵区,4205 | |
| 1713 | +420525,远安县,4205 | |
| 1714 | +420526,兴山县,4205 | |
| 1715 | +420527,秭归县,4205 | |
| 1716 | +420528,长阳土家族自治县,4205 | |
| 1717 | +420529,五峰土家族自治县,4205 | |
| 1718 | +420581,宜都市,4205 | |
| 1719 | +420582,当阳市,4205 | |
| 1720 | +420583,枝江市,4205 | |
| 1721 | +4206,襄阳市,42 | |
| 1722 | +420602,襄城区,4206 | |
| 1723 | +420606,樊城区,4206 | |
| 1724 | +420607,襄州区,4206 | |
| 1725 | +420624,南漳县,4206 | |
| 1726 | +420625,谷城县,4206 | |
| 1727 | +420626,保康县,4206 | |
| 1728 | +420682,老河口市,4206 | |
| 1729 | +420683,枣阳市,4206 | |
| 1730 | +420684,宜城市,4206 | |
| 1731 | +4207,鄂州市,42 | |
| 1732 | +420702,梁子湖区,4207 | |
| 1733 | +420703,华容区,4207 | |
| 1734 | +420704,鄂城区,4207 | |
| 1735 | +4208,荆门市,42 | |
| 1736 | +420802,东宝区,4208 | |
| 1737 | +420804,掇刀区,4208 | |
| 1738 | +420822,沙洋县,4208 | |
| 1739 | +420881,钟祥市,4208 | |
| 1740 | +420882,京山市,4208 | |
| 1741 | +4209,孝感市,42 | |
| 1742 | +420902,孝南区,4209 | |
| 1743 | +420921,孝昌县,4209 | |
| 1744 | +420922,大悟县,4209 | |
| 1745 | +420923,云梦县,4209 | |
| 1746 | +420981,应城市,4209 | |
| 1747 | +420982,安陆市,4209 | |
| 1748 | +420984,汉川市,4209 | |
| 1749 | +4210,荆州市,42 | |
| 1750 | +421002,沙市区,4210 | |
| 1751 | +421003,荆州区,4210 | |
| 1752 | +421022,公安县,4210 | |
| 1753 | +421023,监利县,4210 | |
| 1754 | +421024,江陵县,4210 | |
| 1755 | +421081,石首市,4210 | |
| 1756 | +421083,洪湖市,4210 | |
| 1757 | +421087,松滋市,4210 | |
| 1758 | +4211,黄冈市,42 | |
| 1759 | +421102,黄州区,4211 | |
| 1760 | +421121,团风县,4211 | |
| 1761 | +421122,红安县,4211 | |
| 1762 | +421123,罗田县,4211 | |
| 1763 | +421124,英山县,4211 | |
| 1764 | +421125,浠水县,4211 | |
| 1765 | +421126,蕲春县,4211 | |
| 1766 | +421127,黄梅县,4211 | |
| 1767 | +421181,麻城市,4211 | |
| 1768 | +421182,武穴市,4211 | |
| 1769 | +4212,咸宁市,42 | |
| 1770 | +421202,咸安区,4212 | |
| 1771 | +421221,嘉鱼县,4212 | |
| 1772 | +421222,通城县,4212 | |
| 1773 | +421223,崇阳县,4212 | |
| 1774 | +421224,通山县,4212 | |
| 1775 | +421281,赤壁市,4212 | |
| 1776 | +4213,随州市,42 | |
| 1777 | +421303,曾都区,4213 | |
| 1778 | +421321,随县,4213 | |
| 1779 | +421381,广水市,4213 | |
| 1780 | +4228,恩施土家族苗族自治州,42 | |
| 1781 | +422801,恩施市,4228 | |
| 1782 | +422802,利川市,4228 | |
| 1783 | +422822,建始县,4228 | |
| 1784 | +422823,巴东县,4228 | |
| 1785 | +422825,宣恩县,4228 | |
| 1786 | +422826,咸丰县,4228 | |
| 1787 | +422827,来凤县,4228 | |
| 1788 | +422828,鹤峰县,4228 | |
| 1789 | +429004,仙桃市,42 | |
| 1790 | +429005,潜江市,42 | |
| 1791 | +429006,天门市,42 | |
| 1792 | +429021,神农架林区,42 | |
| 1793 | +43,湖南省, | |
| 1794 | +4301,长沙市,43 | |
| 1795 | +430102,芙蓉区,4301 | |
| 1796 | +430103,天心区,4301 | |
| 1797 | +430104,岳麓区,4301 | |
| 1798 | +430105,开福区,4301 | |
| 1799 | +430111,雨花区,4301 | |
| 1800 | +430112,望城区,4301 | |
| 1801 | +430121,长沙县,4301 | |
| 1802 | +430181,浏阳市,4301 | |
| 1803 | +430182,宁乡市,4301 | |
| 1804 | +4302,株洲市,43 | |
| 1805 | +430202,荷塘区,4302 | |
| 1806 | +430203,芦淞区,4302 | |
| 1807 | +430204,石峰区,4302 | |
| 1808 | +430211,天元区,4302 | |
| 1809 | +430212,渌口区,4302 | |
| 1810 | +430223,攸县,4302 | |
| 1811 | +430224,茶陵县,4302 | |
| 1812 | +430225,炎陵县,4302 | |
| 1813 | +430281,醴陵市,4302 | |
| 1814 | +4303,湘潭市,43 | |
| 1815 | +430302,雨湖区,4303 | |
| 1816 | +430304,岳塘区,4303 | |
| 1817 | +430321,湘潭县,4303 | |
| 1818 | +430381,湘乡市,4303 | |
| 1819 | +430382,韶山市,4303 | |
| 1820 | +4304,衡阳市,43 | |
| 1821 | +430405,珠晖区,4304 | |
| 1822 | +430406,雁峰区,4304 | |
| 1823 | +430407,石鼓区,4304 | |
| 1824 | +430408,蒸湘区,4304 | |
| 1825 | +430412,南岳区,4304 | |
| 1826 | +430421,衡阳县,4304 | |
| 1827 | +430422,衡南县,4304 | |
| 1828 | +430423,衡山县,4304 | |
| 1829 | +430424,衡东县,4304 | |
| 1830 | +430426,祁东县,4304 | |
| 1831 | +430481,耒阳市,4304 | |
| 1832 | +430482,常宁市,4304 | |
| 1833 | +4305,邵阳市,43 | |
| 1834 | +430502,双清区,4305 | |
| 1835 | +430503,大祥区,4305 | |
| 1836 | +430511,北塔区,4305 | |
| 1837 | +430521,邵东县,4305 | |
| 1838 | +430522,新邵县,4305 | |
| 1839 | +430523,邵阳县,4305 | |
| 1840 | +430524,隆回县,4305 | |
| 1841 | +430525,洞口县,4305 | |
| 1842 | +430527,绥宁县,4305 | |
| 1843 | +430528,新宁县,4305 | |
| 1844 | +430529,城步苗族自治县,4305 | |
| 1845 | +430581,武冈市,4305 | |
| 1846 | +4306,岳阳市,43 | |
| 1847 | +430602,岳阳楼区,4306 | |
| 1848 | +430603,云溪区,4306 | |
| 1849 | +430611,君山区,4306 | |
| 1850 | +430621,岳阳县,4306 | |
| 1851 | +430623,华容县,4306 | |
| 1852 | +430624,湘阴县,4306 | |
| 1853 | +430626,平江县,4306 | |
| 1854 | +430681,汨罗市,4306 | |
| 1855 | +430682,临湘市,4306 | |
| 1856 | +4307,常德市,43 | |
| 1857 | +430702,武陵区,4307 | |
| 1858 | +430703,鼎城区,4307 | |
| 1859 | +430721,安乡县,4307 | |
| 1860 | +430722,汉寿县,4307 | |
| 1861 | +430723,澧县,4307 | |
| 1862 | +430724,临澧县,4307 | |
| 1863 | +430725,桃源县,4307 | |
| 1864 | +430726,石门县,4307 | |
| 1865 | +430781,津市市,4307 | |
| 1866 | +4308,张家界市,43 | |
| 1867 | +430802,永定区,4308 | |
| 1868 | +430811,武陵源区,4308 | |
| 1869 | +430821,慈利县,4308 | |
| 1870 | +430822,桑植县,4308 | |
| 1871 | +4309,益阳市,43 | |
| 1872 | +430902,资阳区,4309 | |
| 1873 | +430903,赫山区,4309 | |
| 1874 | +430921,南县,4309 | |
| 1875 | +430922,桃江县,4309 | |
| 1876 | +430923,安化县,4309 | |
| 1877 | +430981,沅江市,4309 | |
| 1878 | +4310,郴州市,43 | |
| 1879 | +431002,北湖区,4310 | |
| 1880 | +431003,苏仙区,4310 | |
| 1881 | +431021,桂阳县,4310 | |
| 1882 | +431022,宜章县,4310 | |
| 1883 | +431023,永兴县,4310 | |
| 1884 | +431024,嘉禾县,4310 | |
| 1885 | +431025,临武县,4310 | |
| 1886 | +431026,汝城县,4310 | |
| 1887 | +431027,桂东县,4310 | |
| 1888 | +431028,安仁县,4310 | |
| 1889 | +431081,资兴市,4310 | |
| 1890 | +4311,永州市,43 | |
| 1891 | +431102,零陵区,4311 | |
| 1892 | +431103,冷水滩区,4311 | |
| 1893 | +431121,祁阳县,4311 | |
| 1894 | +431122,东安县,4311 | |
| 1895 | +431123,双牌县,4311 | |
| 1896 | +431124,道县,4311 | |
| 1897 | +431125,江永县,4311 | |
| 1898 | +431126,宁远县,4311 | |
| 1899 | +431127,蓝山县,4311 | |
| 1900 | +431128,新田县,4311 | |
| 1901 | +431129,江华瑶族自治县,4311 | |
| 1902 | +4312,怀化市,43 | |
| 1903 | +431202,鹤城区,4312 | |
| 1904 | +431221,中方县,4312 | |
| 1905 | +431222,沅陵县,4312 | |
| 1906 | +431223,辰溪县,4312 | |
| 1907 | +431224,溆浦县,4312 | |
| 1908 | +431225,会同县,4312 | |
| 1909 | +431226,麻阳苗族自治县,4312 | |
| 1910 | +431227,新晃侗族自治县,4312 | |
| 1911 | +431228,芷江侗族自治县,4312 | |
| 1912 | +431229,靖州苗族侗族自治县,4312 | |
| 1913 | +431230,通道侗族自治县,4312 | |
| 1914 | +431281,洪江市,4312 | |
| 1915 | +4313,娄底市,43 | |
| 1916 | +431302,娄星区,4313 | |
| 1917 | +431321,双峰县,4313 | |
| 1918 | +431322,新化县,4313 | |
| 1919 | +431381,冷水江市,4313 | |
| 1920 | +431382,涟源市,4313 | |
| 1921 | +4331,湘西土家族苗族自治州,43 | |
| 1922 | +433101,吉首市,4331 | |
| 1923 | +433122,泸溪县,4331 | |
| 1924 | +433123,凤凰县,4331 | |
| 1925 | +433124,花垣县,4331 | |
| 1926 | +433125,保靖县,4331 | |
| 1927 | +433126,古丈县,4331 | |
| 1928 | +433127,永顺县,4331 | |
| 1929 | +433130,龙山县,4331 | |
| 1930 | +44,广东省, | |
| 1931 | +4401,广州市,44 | |
| 1932 | +440103,荔湾区,4401 | |
| 1933 | +440104,越秀区,4401 | |
| 1934 | +440105,海珠区,4401 | |
| 1935 | +440106,天河区,4401 | |
| 1936 | +440111,白云区,4401 | |
| 1937 | +440112,黄埔区,4401 | |
| 1938 | +440113,番禺区,4401 | |
| 1939 | +440114,花都区,4401 | |
| 1940 | +440115,南沙区,4401 | |
| 1941 | +440117,从化区,4401 | |
| 1942 | +440118,增城区,4401 | |
| 1943 | +4402,韶关市,44 | |
| 1944 | +440203,武江区,4402 | |
| 1945 | +440204,浈江区,4402 | |
| 1946 | +440205,曲江区,4402 | |
| 1947 | +440222,始兴县,4402 | |
| 1948 | +440224,仁化县,4402 | |
| 1949 | +440229,翁源县,4402 | |
| 1950 | +440232,乳源瑶族自治县,4402 | |
| 1951 | +440233,新丰县,4402 | |
| 1952 | +440281,乐昌市,4402 | |
| 1953 | +440282,南雄市,4402 | |
| 1954 | +4403,深圳市,44 | |
| 1955 | +440303,罗湖区,4403 | |
| 1956 | +440304,福田区,4403 | |
| 1957 | +440305,南山区,4403 | |
| 1958 | +440306,宝安区,4403 | |
| 1959 | +440307,龙岗区,4403 | |
| 1960 | +440308,盐田区,4403 | |
| 1961 | +440309,龙华区,4403 | |
| 1962 | +440310,坪山区,4403 | |
| 1963 | +440311,光明区,4403 | |
| 1964 | +4404,珠海市,44 | |
| 1965 | +440402,香洲区,4404 | |
| 1966 | +440403,斗门区,4404 | |
| 1967 | +440404,金湾区,4404 | |
| 1968 | +4405,汕头市,44 | |
| 1969 | +440507,龙湖区,4405 | |
| 1970 | +440511,金平区,4405 | |
| 1971 | +440512,濠江区,4405 | |
| 1972 | +440513,潮阳区,4405 | |
| 1973 | +440514,潮南区,4405 | |
| 1974 | +440515,澄海区,4405 | |
| 1975 | +440523,南澳县,4405 | |
| 1976 | +4406,佛山市,44 | |
| 1977 | +440604,禅城区,4406 | |
| 1978 | +440605,南海区,4406 | |
| 1979 | +440606,顺德区,4406 | |
| 1980 | +440607,三水区,4406 | |
| 1981 | +440608,高明区,4406 | |
| 1982 | +4407,江门市,44 | |
| 1983 | +440703,蓬江区,4407 | |
| 1984 | +440704,江海区,4407 | |
| 1985 | +440705,新会区,4407 | |
| 1986 | +440781,台山市,4407 | |
| 1987 | +440783,开平市,4407 | |
| 1988 | +440784,鹤山市,4407 | |
| 1989 | +440785,恩平市,4407 | |
| 1990 | +4408,湛江市,44 | |
| 1991 | +440802,赤坎区,4408 | |
| 1992 | +440803,霞山区,4408 | |
| 1993 | +440804,坡头区,4408 | |
| 1994 | +440811,麻章区,4408 | |
| 1995 | +440823,遂溪县,4408 | |
| 1996 | +440825,徐闻县,4408 | |
| 1997 | +440881,廉江市,4408 | |
| 1998 | +440882,雷州市,4408 | |
| 1999 | +440883,吴川市,4408 | |
| 2000 | +4409,茂名市,44 | |
| 2001 | +440902,茂南区,4409 | |
| 2002 | +440904,电白区,4409 | |
| 2003 | +440981,高州市,4409 | |
| 2004 | +440982,化州市,4409 | |
| 2005 | +440983,信宜市,4409 | |
| 2006 | +4412,肇庆市,44 | |
| 2007 | +441202,端州区,4412 | |
| 2008 | +441203,鼎湖区,4412 | |
| 2009 | +441204,高要区,4412 | |
| 2010 | +441223,广宁县,4412 | |
| 2011 | +441224,怀集县,4412 | |
| 2012 | +441225,封开县,4412 | |
| 2013 | +441226,德庆县,4412 | |
| 2014 | +441284,四会市,4412 | |
| 2015 | +4413,惠州市,44 | |
| 2016 | +441302,惠城区,4413 | |
| 2017 | +441303,惠阳区,4413 | |
| 2018 | +441322,博罗县,4413 | |
| 2019 | +441323,惠东县,4413 | |
| 2020 | +441324,龙门县,4413 | |
| 2021 | +4414,梅州市,44 | |
| 2022 | +441402,梅江区,4414 | |
| 2023 | +441403,梅县区,4414 | |
| 2024 | +441422,大埔县,4414 | |
| 2025 | +441423,丰顺县,4414 | |
| 2026 | +441424,五华县,4414 | |
| 2027 | +441426,平远县,4414 | |
| 2028 | +441427,蕉岭县,4414 | |
| 2029 | +441481,兴宁市,4414 | |
| 2030 | +4415,汕尾市,44 | |
| 2031 | +441502,城区,4415 | |
| 2032 | +441521,海丰县,4415 | |
| 2033 | +441523,陆河县,4415 | |
| 2034 | +441581,陆丰市,4415 | |
| 2035 | +4416,河源市,44 | |
| 2036 | +441602,源城区,4416 | |
| 2037 | +441621,紫金县,4416 | |
| 2038 | +441622,龙川县,4416 | |
| 2039 | +441623,连平县,4416 | |
| 2040 | +441624,和平县,4416 | |
| 2041 | +441625,东源县,4416 | |
| 2042 | +4417,阳江市,44 | |
| 2043 | +441702,江城区,4417 | |
| 2044 | +441704,阳东区,4417 | |
| 2045 | +441721,阳西县,4417 | |
| 2046 | +441781,阳春市,4417 | |
| 2047 | +4418,清远市,44 | |
| 2048 | +441802,清城区,4418 | |
| 2049 | +441803,清新区,4418 | |
| 2050 | +441821,佛冈县,4418 | |
| 2051 | +441823,阳山县,4418 | |
| 2052 | +441825,连山壮族瑶族自治县,4418 | |
| 2053 | +441826,连南瑶族自治县,4418 | |
| 2054 | +441881,英德市,4418 | |
| 2055 | +441882,连州市,4418 | |
| 2056 | +4419,东莞市,44 | |
| 2057 | +4420,中山市,44 | |
| 2058 | +4451,潮州市,44 | |
| 2059 | +445102,湘桥区,4451 | |
| 2060 | +445103,潮安区,4451 | |
| 2061 | +445122,饶平县,4451 | |
| 2062 | +4452,揭阳市,44 | |
| 2063 | +445202,榕城区,4452 | |
| 2064 | +445203,揭东区,4452 | |
| 2065 | +445222,揭西县,4452 | |
| 2066 | +445224,惠来县,4452 | |
| 2067 | +445281,普宁市,4452 | |
| 2068 | +4453,云浮市,44 | |
| 2069 | +445302,云城区,4453 | |
| 2070 | +445303,云安区,4453 | |
| 2071 | +445321,新兴县,4453 | |
| 2072 | +445322,郁南县,4453 | |
| 2073 | +445381,罗定市,4453 | |
| 2074 | +45,广西壮族自治区, | |
| 2075 | +4501,南宁市,45 | |
| 2076 | +450102,兴宁区,4501 | |
| 2077 | +450103,青秀区,4501 | |
| 2078 | +450105,江南区,4501 | |
| 2079 | +450107,西乡塘区,4501 | |
| 2080 | +450108,良庆区,4501 | |
| 2081 | +450109,邕宁区,4501 | |
| 2082 | +450110,武鸣区,4501 | |
| 2083 | +450123,隆安县,4501 | |
| 2084 | +450124,马山县,4501 | |
| 2085 | +450125,上林县,4501 | |
| 2086 | +450126,宾阳县,4501 | |
| 2087 | +450127,横县,4501 | |
| 2088 | +4502,柳州市,45 | |
| 2089 | +450202,城中区,4502 | |
| 2090 | +450203,鱼峰区,4502 | |
| 2091 | +450204,柳南区,4502 | |
| 2092 | +450205,柳北区,4502 | |
| 2093 | +450206,柳江区,4502 | |
| 2094 | +450222,柳城县,4502 | |
| 2095 | +450223,鹿寨县,4502 | |
| 2096 | +450224,融安县,4502 | |
| 2097 | +450225,融水苗族自治县,4502 | |
| 2098 | +450226,三江侗族自治县,4502 | |
| 2099 | +4503,桂林市,45 | |
| 2100 | +450302,秀峰区,4503 | |
| 2101 | +450303,叠彩区,4503 | |
| 2102 | +450304,象山区,4503 | |
| 2103 | +450305,七星区,4503 | |
| 2104 | +450311,雁山区,4503 | |
| 2105 | +450312,临桂区,4503 | |
| 2106 | +450321,阳朔县,4503 | |
| 2107 | +450323,灵川县,4503 | |
| 2108 | +450324,全州县,4503 | |
| 2109 | +450325,兴安县,4503 | |
| 2110 | +450326,永福县,4503 | |
| 2111 | +450327,灌阳县,4503 | |
| 2112 | +450328,龙胜各族自治县,4503 | |
| 2113 | +450329,资源县,4503 | |
| 2114 | +450330,平乐县,4503 | |
| 2115 | +450332,恭城瑶族自治县,4503 | |
| 2116 | +450381,荔浦市,4503 | |
| 2117 | +4504,梧州市,45 | |
| 2118 | +450403,万秀区,4504 | |
| 2119 | +450405,长洲区,4504 | |
| 2120 | +450406,龙圩区,4504 | |
| 2121 | +450421,苍梧县,4504 | |
| 2122 | +450422,藤县,4504 | |
| 2123 | +450423,蒙山县,4504 | |
| 2124 | +450481,岑溪市,4504 | |
| 2125 | +4505,北海市,45 | |
| 2126 | +450502,海城区,4505 | |
| 2127 | +450503,银海区,4505 | |
| 2128 | +450512,铁山港区,4505 | |
| 2129 | +450521,合浦县,4505 | |
| 2130 | +4506,防城港市,45 | |
| 2131 | +450602,港口区,4506 | |
| 2132 | +450603,防城区,4506 | |
| 2133 | +450621,上思县,4506 | |
| 2134 | +450681,东兴市,4506 | |
| 2135 | +4507,钦州市,45 | |
| 2136 | +450702,钦南区,4507 | |
| 2137 | +450703,钦北区,4507 | |
| 2138 | +450721,灵山县,4507 | |
| 2139 | +450722,浦北县,4507 | |
| 2140 | +4508,贵港市,45 | |
| 2141 | +450802,港北区,4508 | |
| 2142 | +450803,港南区,4508 | |
| 2143 | +450804,覃塘区,4508 | |
| 2144 | +450821,平南县,4508 | |
| 2145 | +450881,桂平市,4508 | |
| 2146 | +4509,玉林市,45 | |
| 2147 | +450902,玉州区,4509 | |
| 2148 | +450903,福绵区,4509 | |
| 2149 | +450921,容县,4509 | |
| 2150 | +450922,陆川县,4509 | |
| 2151 | +450923,博白县,4509 | |
| 2152 | +450924,兴业县,4509 | |
| 2153 | +450981,北流市,4509 | |
| 2154 | +4510,百色市,45 | |
| 2155 | +451002,右江区,4510 | |
| 2156 | +451021,田阳县,4510 | |
| 2157 | +451022,田东县,4510 | |
| 2158 | +451023,平果县,4510 | |
| 2159 | +451024,德保县,4510 | |
| 2160 | +451026,那坡县,4510 | |
| 2161 | +451027,凌云县,4510 | |
| 2162 | +451028,乐业县,4510 | |
| 2163 | +451029,田林县,4510 | |
| 2164 | +451030,西林县,4510 | |
| 2165 | +451031,隆林各族自治县,4510 | |
| 2166 | +451081,靖西市,4510 | |
| 2167 | +4511,贺州市,45 | |
| 2168 | +451102,八步区,4511 | |
| 2169 | +451103,平桂区,4511 | |
| 2170 | +451121,昭平县,4511 | |
| 2171 | +451122,钟山县,4511 | |
| 2172 | +451123,富川瑶族自治县,4511 | |
| 2173 | +4512,河池市,45 | |
| 2174 | +451202,金城江区,4512 | |
| 2175 | +451203,宜州区,4512 | |
| 2176 | +451221,南丹县,4512 | |
| 2177 | +451222,天峨县,4512 | |
| 2178 | +451223,凤山县,4512 | |
| 2179 | +451224,东兰县,4512 | |
| 2180 | +451225,罗城仫佬族自治县,4512 | |
| 2181 | +451226,环江毛南族自治县,4512 | |
| 2182 | +451227,巴马瑶族自治县,4512 | |
| 2183 | +451228,都安瑶族自治县,4512 | |
| 2184 | +451229,大化瑶族自治县,4512 | |
| 2185 | +4513,来宾市,45 | |
| 2186 | +451302,兴宾区,4513 | |
| 2187 | +451321,忻城县,4513 | |
| 2188 | +451322,象州县,4513 | |
| 2189 | +451323,武宣县,4513 | |
| 2190 | +451324,金秀瑶族自治县,4513 | |
| 2191 | +451381,合山市,4513 | |
| 2192 | +4514,崇左市,45 | |
| 2193 | +451402,江州区,4514 | |
| 2194 | +451421,扶绥县,4514 | |
| 2195 | +451422,宁明县,4514 | |
| 2196 | +451423,龙州县,4514 | |
| 2197 | +451424,大新县,4514 | |
| 2198 | +451425,天等县,4514 | |
| 2199 | +451481,凭祥市,4514 | |
| 2200 | +46,海南省, | |
| 2201 | +4601,海口市,46 | |
| 2202 | +460105,秀英区,4601 | |
| 2203 | +460106,龙华区,4601 | |
| 2204 | +460107,琼山区,4601 | |
| 2205 | +460108,美兰区,4601 | |
| 2206 | +4602,三亚市,46 | |
| 2207 | +460202,海棠区,4602 | |
| 2208 | +460203,吉阳区,4602 | |
| 2209 | +460204,天涯区,4602 | |
| 2210 | +460205,崖州区,4602 | |
| 2211 | +4603,三沙市,46 | |
| 2212 | +4604,儋州市,46 | |
| 2213 | +469001,五指山市,46 | |
| 2214 | +469002,琼海市,46 | |
| 2215 | +469005,文昌市,46 | |
| 2216 | +469006,万宁市,46 | |
| 2217 | +469007,东方市,46 | |
| 2218 | +469021,定安县,46 | |
| 2219 | +469022,屯昌县,46 | |
| 2220 | +469023,澄迈县,46 | |
| 2221 | +469024,临高县,46 | |
| 2222 | +469025,白沙黎族自治县,46 | |
| 2223 | +469026,昌江黎族自治县,46 | |
| 2224 | +469027,乐东黎族自治县,46 | |
| 2225 | +469028,陵水黎族自治县,46 | |
| 2226 | +469029,保亭黎族苗族自治县,46 | |
| 2227 | +469030,琼中黎族苗族自治县,46 | |
| 2228 | +50,重庆市, | |
| 2229 | +500101,万州区,50 | |
| 2230 | +500102,涪陵区,50 | |
| 2231 | +500103,渝中区,50 | |
| 2232 | +500104,大渡口区,50 | |
| 2233 | +500105,江北区,50 | |
| 2234 | +500106,沙坪坝区,50 | |
| 2235 | +500107,九龙坡区,50 | |
| 2236 | +500108,南岸区,50 | |
| 2237 | +500109,北碚区,50 | |
| 2238 | +500110,綦江区,50 | |
| 2239 | +500111,大足区,50 | |
| 2240 | +500112,渝北区,50 | |
| 2241 | +500113,巴南区,50 | |
| 2242 | +500114,黔江区,50 | |
| 2243 | +500115,长寿区,50 | |
| 2244 | +500116,江津区,50 | |
| 2245 | +500117,合川区,50 | |
| 2246 | +500118,永川区,50 | |
| 2247 | +500119,南川区,50 | |
| 2248 | +500120,璧山区,50 | |
| 2249 | +500151,铜梁区,50 | |
| 2250 | +500152,潼南区,50 | |
| 2251 | +500153,荣昌区,50 | |
| 2252 | +500154,开州区,50 | |
| 2253 | +500155,梁平区,50 | |
| 2254 | +500156,武隆区,50 | |
| 2255 | +500229,城口县,50 | |
| 2256 | +500230,丰都县,50 | |
| 2257 | +500231,垫江县,50 | |
| 2258 | +500233,忠县,50 | |
| 2259 | +500235,云阳县,50 | |
| 2260 | +500236,奉节县,50 | |
| 2261 | +500237,巫山县,50 | |
| 2262 | +500238,巫溪县,50 | |
| 2263 | +500240,石柱土家族自治县,50 | |
| 2264 | +500241,秀山土家族苗族自治县,50 | |
| 2265 | +500242,酉阳土家族苗族自治县,50 | |
| 2266 | +500243,彭水苗族土家族自治县,50 | |
| 2267 | +51,四川省, | |
| 2268 | +5101,成都市,51 | |
| 2269 | +510104,锦江区,5101 | |
| 2270 | +510105,青羊区,5101 | |
| 2271 | +510106,金牛区,5101 | |
| 2272 | +510107,武侯区,5101 | |
| 2273 | +510108,成华区,5101 | |
| 2274 | +510112,龙泉驿区,5101 | |
| 2275 | +510113,青白江区,5101 | |
| 2276 | +510114,新都区,5101 | |
| 2277 | +510115,温江区,5101 | |
| 2278 | +510116,双流区,5101 | |
| 2279 | +510117,郫都区,5101 | |
| 2280 | +510121,金堂县,5101 | |
| 2281 | +510129,大邑县,5101 | |
| 2282 | +510131,蒲江县,5101 | |
| 2283 | +510132,新津县,5101 | |
| 2284 | +510181,都江堰市,5101 | |
| 2285 | +510182,彭州市,5101 | |
| 2286 | +510183,邛崃市,5101 | |
| 2287 | +510184,崇州市,5101 | |
| 2288 | +510185,简阳市,5101 | |
| 2289 | +5103,自贡市,51 | |
| 2290 | +510302,自流井区,5103 | |
| 2291 | +510303,贡井区,5103 | |
| 2292 | +510304,大安区,5103 | |
| 2293 | +510311,沿滩区,5103 | |
| 2294 | +510321,荣县,5103 | |
| 2295 | +510322,富顺县,5103 | |
| 2296 | +5104,攀枝花市,51 | |
| 2297 | +510402,东区,5104 | |
| 2298 | +510403,西区,5104 | |
| 2299 | +510411,仁和区,5104 | |
| 2300 | +510421,米易县,5104 | |
| 2301 | +510422,盐边县,5104 | |
| 2302 | +5105,泸州市,51 | |
| 2303 | +510502,江阳区,5105 | |
| 2304 | +510503,纳溪区,5105 | |
| 2305 | +510504,龙马潭区,5105 | |
| 2306 | +510521,泸县,5105 | |
| 2307 | +510522,合江县,5105 | |
| 2308 | +510524,叙永县,5105 | |
| 2309 | +510525,古蔺县,5105 | |
| 2310 | +5106,德阳市,51 | |
| 2311 | +510603,旌阳区,5106 | |
| 2312 | +510604,罗江区,5106 | |
| 2313 | +510623,中江县,5106 | |
| 2314 | +510681,广汉市,5106 | |
| 2315 | +510682,什邡市,5106 | |
| 2316 | +510683,绵竹市,5106 | |
| 2317 | +5107,绵阳市,51 | |
| 2318 | +510703,涪城区,5107 | |
| 2319 | +510704,游仙区,5107 | |
| 2320 | +510705,安州区,5107 | |
| 2321 | +510722,三台县,5107 | |
| 2322 | +510723,盐亭县,5107 | |
| 2323 | +510725,梓潼县,5107 | |
| 2324 | +510726,北川羌族自治县,5107 | |
| 2325 | +510727,平武县,5107 | |
| 2326 | +510781,江油市,5107 | |
| 2327 | +5108,广元市,51 | |
| 2328 | +510802,利州区,5108 | |
| 2329 | +510811,昭化区,5108 | |
| 2330 | +510812,朝天区,5108 | |
| 2331 | +510821,旺苍县,5108 | |
| 2332 | +510822,青川县,5108 | |
| 2333 | +510823,剑阁县,5108 | |
| 2334 | +510824,苍溪县,5108 | |
| 2335 | +5109,遂宁市,51 | |
| 2336 | +510903,船山区,5109 | |
| 2337 | +510904,安居区,5109 | |
| 2338 | +510921,蓬溪县,5109 | |
| 2339 | +510922,射洪县,5109 | |
| 2340 | +510923,大英县,5109 | |
| 2341 | +5110,内江市,51 | |
| 2342 | +511002,市中区,5110 | |
| 2343 | +511011,东兴区,5110 | |
| 2344 | +511024,威远县,5110 | |
| 2345 | +511025,资中县,5110 | |
| 2346 | +511083,隆昌市,5110 | |
| 2347 | +5111,乐山市,51 | |
| 2348 | +511102,市中区,5111 | |
| 2349 | +511111,沙湾区,5111 | |
| 2350 | +511112,五通桥区,5111 | |
| 2351 | +511113,金口河区,5111 | |
| 2352 | +511123,犍为县,5111 | |
| 2353 | +511124,井研县,5111 | |
| 2354 | +511126,夹江县,5111 | |
| 2355 | +511129,沐川县,5111 | |
| 2356 | +511132,峨边彝族自治县,5111 | |
| 2357 | +511133,马边彝族自治县,5111 | |
| 2358 | +511181,峨眉山市,5111 | |
| 2359 | +5113,南充市,51 | |
| 2360 | +511302,顺庆区,5113 | |
| 2361 | +511303,高坪区,5113 | |
| 2362 | +511304,嘉陵区,5113 | |
| 2363 | +511321,南部县,5113 | |
| 2364 | +511322,营山县,5113 | |
| 2365 | +511323,蓬安县,5113 | |
| 2366 | +511324,仪陇县,5113 | |
| 2367 | +511325,西充县,5113 | |
| 2368 | +511381,阆中市,5113 | |
| 2369 | +5114,眉山市,51 | |
| 2370 | +511402,东坡区,5114 | |
| 2371 | +511403,彭山区,5114 | |
| 2372 | +511421,仁寿县,5114 | |
| 2373 | +511423,洪雅县,5114 | |
| 2374 | +511424,丹棱县,5114 | |
| 2375 | +511425,青神县,5114 | |
| 2376 | +5115,宜宾市,51 | |
| 2377 | +511502,翠屏区,5115 | |
| 2378 | +511503,南溪区,5115 | |
| 2379 | +511504,叙州区,5115 | |
| 2380 | +511523,江安县,5115 | |
| 2381 | +511524,长宁县,5115 | |
| 2382 | +511525,高县,5115 | |
| 2383 | +511526,珙县,5115 | |
| 2384 | +511527,筠连县,5115 | |
| 2385 | +511528,兴文县,5115 | |
| 2386 | +511529,屏山县,5115 | |
| 2387 | +5116,广安市,51 | |
| 2388 | +511602,广安区,5116 | |
| 2389 | +511603,前锋区,5116 | |
| 2390 | +511621,岳池县,5116 | |
| 2391 | +511622,武胜县,5116 | |
| 2392 | +511623,邻水县,5116 | |
| 2393 | +511681,华蓥市,5116 | |
| 2394 | +5117,达州市,51 | |
| 2395 | +511702,通川区,5117 | |
| 2396 | +511703,达川区,5117 | |
| 2397 | +511722,宣汉县,5117 | |
| 2398 | +511723,开江县,5117 | |
| 2399 | +511724,大竹县,5117 | |
| 2400 | +511725,渠县,5117 | |
| 2401 | +511781,万源市,5117 | |
| 2402 | +5118,雅安市,51 | |
| 2403 | +511802,雨城区,5118 | |
| 2404 | +511803,名山区,5118 | |
| 2405 | +511822,荥经县,5118 | |
| 2406 | +511823,汉源县,5118 | |
| 2407 | +511824,石棉县,5118 | |
| 2408 | +511825,天全县,5118 | |
| 2409 | +511826,芦山县,5118 | |
| 2410 | +511827,宝兴县,5118 | |
| 2411 | +5119,巴中市,51 | |
| 2412 | +511902,巴州区,5119 | |
| 2413 | +511903,恩阳区,5119 | |
| 2414 | +511921,通江县,5119 | |
| 2415 | +511922,南江县,5119 | |
| 2416 | +511923,平昌县,5119 | |
| 2417 | +5120,资阳市,51 | |
| 2418 | +512002,雁江区,5120 | |
| 2419 | +512021,安岳县,5120 | |
| 2420 | +512022,乐至县,5120 | |
| 2421 | +5132,阿坝藏族羌族自治州,51 | |
| 2422 | +513201,马尔康市,5132 | |
| 2423 | +513221,汶川县,5132 | |
| 2424 | +513222,理县,5132 | |
| 2425 | +513223,茂县,5132 | |
| 2426 | +513224,松潘县,5132 | |
| 2427 | +513225,九寨沟县,5132 | |
| 2428 | +513226,金川县,5132 | |
| 2429 | +513227,小金县,5132 | |
| 2430 | +513228,黑水县,5132 | |
| 2431 | +513230,壤塘县,5132 | |
| 2432 | +513231,阿坝县,5132 | |
| 2433 | +513232,若尔盖县,5132 | |
| 2434 | +513233,红原县,5132 | |
| 2435 | +5133,甘孜藏族自治州,51 | |
| 2436 | +513301,康定市,5133 | |
| 2437 | +513322,泸定县,5133 | |
| 2438 | +513323,丹巴县,5133 | |
| 2439 | +513324,九龙县,5133 | |
| 2440 | +513325,雅江县,5133 | |
| 2441 | +513326,道孚县,5133 | |
| 2442 | +513327,炉霍县,5133 | |
| 2443 | +513328,甘孜县,5133 | |
| 2444 | +513329,新龙县,5133 | |
| 2445 | +513330,德格县,5133 | |
| 2446 | +513331,白玉县,5133 | |
| 2447 | +513332,石渠县,5133 | |
| 2448 | +513333,色达县,5133 | |
| 2449 | +513334,理塘县,5133 | |
| 2450 | +513335,巴塘县,5133 | |
| 2451 | +513336,乡城县,5133 | |
| 2452 | +513337,稻城县,5133 | |
| 2453 | +513338,得荣县,5133 | |
| 2454 | +5134,凉山彝族自治州,51 | |
| 2455 | +513401,西昌市,5134 | |
| 2456 | +513422,木里藏族自治县,5134 | |
| 2457 | +513423,盐源县,5134 | |
| 2458 | +513424,德昌县,5134 | |
| 2459 | +513425,会理县,5134 | |
| 2460 | +513426,会东县,5134 | |
| 2461 | +513427,宁南县,5134 | |
| 2462 | +513428,普格县,5134 | |
| 2463 | +513429,布拖县,5134 | |
| 2464 | +513430,金阳县,5134 | |
| 2465 | +513431,昭觉县,5134 | |
| 2466 | +513432,喜德县,5134 | |
| 2467 | +513433,冕宁县,5134 | |
| 2468 | +513434,越西县,5134 | |
| 2469 | +513435,甘洛县,5134 | |
| 2470 | +513436,美姑县,5134 | |
| 2471 | +513437,雷波县,5134 | |
| 2472 | +52,贵州省, | |
| 2473 | +5201,贵阳市,52 | |
| 2474 | +520102,南明区,5201 | |
| 2475 | +520103,云岩区,5201 | |
| 2476 | +520111,花溪区,5201 | |
| 2477 | +520112,乌当区,5201 | |
| 2478 | +520113,白云区,5201 | |
| 2479 | +520115,观山湖区,5201 | |
| 2480 | +520121,开阳县,5201 | |
| 2481 | +520122,息烽县,5201 | |
| 2482 | +520123,修文县,5201 | |
| 2483 | +520181,清镇市,5201 | |
| 2484 | +5202,六盘水市,52 | |
| 2485 | +520201,钟山区,5202 | |
| 2486 | +520203,六枝特区,5202 | |
| 2487 | +520221,水城县,5202 | |
| 2488 | +520281,盘州市,5202 | |
| 2489 | +5203,遵义市,52 | |
| 2490 | +520302,红花岗区,5203 | |
| 2491 | +520303,汇川区,5203 | |
| 2492 | +520304,播州区,5203 | |
| 2493 | +520322,桐梓县,5203 | |
| 2494 | +520323,绥阳县,5203 | |
| 2495 | +520324,正安县,5203 | |
| 2496 | +520325,道真仡佬族苗族自治县,5203 | |
| 2497 | +520326,务川仡佬族苗族自治县,5203 | |
| 2498 | +520327,凤冈县,5203 | |
| 2499 | +520328,湄潭县,5203 | |
| 2500 | +520329,余庆县,5203 | |
| 2501 | +520330,习水县,5203 | |
| 2502 | +520381,赤水市,5203 | |
| 2503 | +520382,仁怀市,5203 | |
| 2504 | +5204,安顺市,52 | |
| 2505 | +520402,西秀区,5204 | |
| 2506 | +520403,平坝区,5204 | |
| 2507 | +520422,普定县,5204 | |
| 2508 | +520423,镇宁布依族苗族自治县,5204 | |
| 2509 | +520424,关岭布依族苗族自治县,5204 | |
| 2510 | +520425,紫云苗族布依族自治县,5204 | |
| 2511 | +5205,毕节市,52 | |
| 2512 | +520502,七星关区,5205 | |
| 2513 | +520521,大方县,5205 | |
| 2514 | +520522,黔西县,5205 | |
| 2515 | +520523,金沙县,5205 | |
| 2516 | +520524,织金县,5205 | |
| 2517 | +520525,纳雍县,5205 | |
| 2518 | +520526,威宁彝族回族苗族自治县,5205 | |
| 2519 | +520527,赫章县,5205 | |
| 2520 | +5206,铜仁市,52 | |
| 2521 | +520602,碧江区,5206 | |
| 2522 | +520603,万山区,5206 | |
| 2523 | +520621,江口县,5206 | |
| 2524 | +520622,玉屏侗族自治县,5206 | |
| 2525 | +520623,石阡县,5206 | |
| 2526 | +520624,思南县,5206 | |
| 2527 | +520625,印江土家族苗族自治县,5206 | |
| 2528 | +520626,德江县,5206 | |
| 2529 | +520627,沿河土家族自治县,5206 | |
| 2530 | +520628,松桃苗族自治县,5206 | |
| 2531 | +5223,黔西南布依族苗族自治州,52 | |
| 2532 | +522301,兴义市,5223 | |
| 2533 | +522302,兴仁市,5223 | |
| 2534 | +522323,普安县,5223 | |
| 2535 | +522324,晴隆县,5223 | |
| 2536 | +522325,贞丰县,5223 | |
| 2537 | +522326,望谟县,5223 | |
| 2538 | +522327,册亨县,5223 | |
| 2539 | +522328,安龙县,5223 | |
| 2540 | +5226,黔东南苗族侗族自治州,52 | |
| 2541 | +522601,凯里市,5226 | |
| 2542 | +522622,黄平县,5226 | |
| 2543 | +522623,施秉县,5226 | |
| 2544 | +522624,三穗县,5226 | |
| 2545 | +522625,镇远县,5226 | |
| 2546 | +522626,岑巩县,5226 | |
| 2547 | +522627,天柱县,5226 | |
| 2548 | +522628,锦屏县,5226 | |
| 2549 | +522629,剑河县,5226 | |
| 2550 | +522630,台江县,5226 | |
| 2551 | +522631,黎平县,5226 | |
| 2552 | +522632,榕江县,5226 | |
| 2553 | +522633,从江县,5226 | |
| 2554 | +522634,雷山县,5226 | |
| 2555 | +522635,麻江县,5226 | |
| 2556 | +522636,丹寨县,5226 | |
| 2557 | +5227,黔南布依族苗族自治州,52 | |
| 2558 | +522701,都匀市,5227 | |
| 2559 | +522702,福泉市,5227 | |
| 2560 | +522722,荔波县,5227 | |
| 2561 | +522723,贵定县,5227 | |
| 2562 | +522725,瓮安县,5227 | |
| 2563 | +522726,独山县,5227 | |
| 2564 | +522727,平塘县,5227 | |
| 2565 | +522728,罗甸县,5227 | |
| 2566 | +522729,长顺县,5227 | |
| 2567 | +522730,龙里县,5227 | |
| 2568 | +522731,惠水县,5227 | |
| 2569 | +522732,三都水族自治县,5227 | |
| 2570 | +53,云南省, | |
| 2571 | +5301,昆明市,53 | |
| 2572 | +530102,五华区,5301 | |
| 2573 | +530103,盘龙区,5301 | |
| 2574 | +530111,官渡区,5301 | |
| 2575 | +530112,西山区,5301 | |
| 2576 | +530113,东川区,5301 | |
| 2577 | +530114,呈贡区,5301 | |
| 2578 | +530115,晋宁区,5301 | |
| 2579 | +530124,富民县,5301 | |
| 2580 | +530125,宜良县,5301 | |
| 2581 | +530126,石林彝族自治县,5301 | |
| 2582 | +530127,嵩明县,5301 | |
| 2583 | +530128,禄劝彝族苗族自治县,5301 | |
| 2584 | +530129,寻甸回族彝族自治县,5301 | |
| 2585 | +530181,安宁市,5301 | |
| 2586 | +5303,曲靖市,53 | |
| 2587 | +530302,麒麟区,5303 | |
| 2588 | +530303,沾益区,5303 | |
| 2589 | +530304,马龙区,5303 | |
| 2590 | +530322,陆良县,5303 | |
| 2591 | +530323,师宗县,5303 | |
| 2592 | +530324,罗平县,5303 | |
| 2593 | +530325,富源县,5303 | |
| 2594 | +530326,会泽县,5303 | |
| 2595 | +530381,宣威市,5303 | |
| 2596 | +5304,玉溪市,53 | |
| 2597 | +530402,红塔区,5304 | |
| 2598 | +530403,江川区,5304 | |
| 2599 | +530422,澄江县,5304 | |
| 2600 | +530423,通海县,5304 | |
| 2601 | +530424,华宁县,5304 | |
| 2602 | +530425,易门县,5304 | |
| 2603 | +530426,峨山彝族自治县,5304 | |
| 2604 | +530427,新平彝族傣族自治县,5304 | |
| 2605 | +530428,元江哈尼族彝族傣族自治县,5304 | |
| 2606 | +5305,保山市,53 | |
| 2607 | +530502,隆阳区,5305 | |
| 2608 | +530521,施甸县,5305 | |
| 2609 | +530523,龙陵县,5305 | |
| 2610 | +530524,昌宁县,5305 | |
| 2611 | +530581,腾冲市,5305 | |
| 2612 | +5306,昭通市,53 | |
| 2613 | +530602,昭阳区,5306 | |
| 2614 | +530621,鲁甸县,5306 | |
| 2615 | +530622,巧家县,5306 | |
| 2616 | +530623,盐津县,5306 | |
| 2617 | +530624,大关县,5306 | |
| 2618 | +530625,永善县,5306 | |
| 2619 | +530626,绥江县,5306 | |
| 2620 | +530627,镇雄县,5306 | |
| 2621 | +530628,彝良县,5306 | |
| 2622 | +530629,威信县,5306 | |
| 2623 | +530681,水富市,5306 | |
| 2624 | +5307,丽江市,53 | |
| 2625 | +530702,古城区,5307 | |
| 2626 | +530721,玉龙纳西族自治县,5307 | |
| 2627 | +530722,永胜县,5307 | |
| 2628 | +530723,华坪县,5307 | |
| 2629 | +530724,宁蒗彝族自治县,5307 | |
| 2630 | +5308,普洱市,53 | |
| 2631 | +530802,思茅区,5308 | |
| 2632 | +530821,宁洱哈尼族彝族自治县,5308 | |
| 2633 | +530822,墨江哈尼族自治县,5308 | |
| 2634 | +530823,景东彝族自治县,5308 | |
| 2635 | +530824,景谷傣族彝族自治县,5308 | |
| 2636 | +530825,镇沅彝族哈尼族拉祜族自治县,5308 | |
| 2637 | +530826,江城哈尼族彝族自治县,5308 | |
| 2638 | +530827,孟连傣族拉祜族佤族自治县,5308 | |
| 2639 | +530828,澜沧拉祜族自治县,5308 | |
| 2640 | +530829,西盟佤族自治县,5308 | |
| 2641 | +5309,临沧市,53 | |
| 2642 | +530902,临翔区,5309 | |
| 2643 | +530921,凤庆县,5309 | |
| 2644 | +530922,云县,5309 | |
| 2645 | +530923,永德县,5309 | |
| 2646 | +530924,镇康县,5309 | |
| 2647 | +530925,双江拉祜族佤族布朗族傣族自治县,5309 | |
| 2648 | +530926,耿马傣族佤族自治县,5309 | |
| 2649 | +530927,沧源佤族自治县,5309 | |
| 2650 | +5323,楚雄彝族自治州,53 | |
| 2651 | +532301,楚雄市,5323 | |
| 2652 | +532322,双柏县,5323 | |
| 2653 | +532323,牟定县,5323 | |
| 2654 | +532324,南华县,5323 | |
| 2655 | +532325,姚安县,5323 | |
| 2656 | +532326,大姚县,5323 | |
| 2657 | +532327,永仁县,5323 | |
| 2658 | +532328,元谋县,5323 | |
| 2659 | +532329,武定县,5323 | |
| 2660 | +532331,禄丰县,5323 | |
| 2661 | +5325,红河哈尼族彝族自治州,53 | |
| 2662 | +532501,个旧市,5325 | |
| 2663 | +532502,开远市,5325 | |
| 2664 | +532503,蒙自市,5325 | |
| 2665 | +532504,弥勒市,5325 | |
| 2666 | +532523,屏边苗族自治县,5325 | |
| 2667 | +532524,建水县,5325 | |
| 2668 | +532525,石屏县,5325 | |
| 2669 | +532527,泸西县,5325 | |
| 2670 | +532528,元阳县,5325 | |
| 2671 | +532529,红河县,5325 | |
| 2672 | +532530,金平苗族瑶族傣族自治县,5325 | |
| 2673 | +532531,绿春县,5325 | |
| 2674 | +532532,河口瑶族自治县,5325 | |
| 2675 | +5326,文山壮族苗族自治州,53 | |
| 2676 | +532601,文山市,5326 | |
| 2677 | +532622,砚山县,5326 | |
| 2678 | +532623,西畴县,5326 | |
| 2679 | +532624,麻栗坡县,5326 | |
| 2680 | +532625,马关县,5326 | |
| 2681 | +532626,丘北县,5326 | |
| 2682 | +532627,广南县,5326 | |
| 2683 | +532628,富宁县,5326 | |
| 2684 | +5328,西双版纳傣族自治州,53 | |
| 2685 | +532801,景洪市,5328 | |
| 2686 | +532822,勐海县,5328 | |
| 2687 | +532823,勐腊县,5328 | |
| 2688 | +5329,大理白族自治州,53 | |
| 2689 | +532901,大理市,5329 | |
| 2690 | +532922,漾濞彝族自治县,5329 | |
| 2691 | +532923,祥云县,5329 | |
| 2692 | +532924,宾川县,5329 | |
| 2693 | +532925,弥渡县,5329 | |
| 2694 | +532926,南涧彝族自治县,5329 | |
| 2695 | +532927,巍山彝族回族自治县,5329 | |
| 2696 | +532928,永平县,5329 | |
| 2697 | +532929,云龙县,5329 | |
| 2698 | +532930,洱源县,5329 | |
| 2699 | +532931,剑川县,5329 | |
| 2700 | +532932,鹤庆县,5329 | |
| 2701 | +5331,德宏傣族景颇族自治州,53 | |
| 2702 | +533102,瑞丽市,5331 | |
| 2703 | +533103,芒市,5331 | |
| 2704 | +533122,梁河县,5331 | |
| 2705 | +533123,盈江县,5331 | |
| 2706 | +533124,陇川县,5331 | |
| 2707 | +5333,怒江傈僳族自治州,53 | |
| 2708 | +533301,泸水市,5333 | |
| 2709 | +533323,福贡县,5333 | |
| 2710 | +533324,贡山独龙族怒族自治县,5333 | |
| 2711 | +533325,兰坪白族普米族自治县,5333 | |
| 2712 | +5334,迪庆藏族自治州,53 | |
| 2713 | +533401,香格里拉市,5334 | |
| 2714 | +533422,德钦县,5334 | |
| 2715 | +533423,维西傈僳族自治县,5334 | |
| 2716 | +54,西藏自治区, | |
| 2717 | +5401,拉萨市,54 | |
| 2718 | +540102,城关区,5401 | |
| 2719 | +540103,堆龙德庆区,5401 | |
| 2720 | +540104,达孜区,5401 | |
| 2721 | +540121,林周县,5401 | |
| 2722 | +540122,当雄县,5401 | |
| 2723 | +540123,尼木县,5401 | |
| 2724 | +540124,曲水县,5401 | |
| 2725 | +540127,墨竹工卡县,5401 | |
| 2726 | +5402,日喀则市,54 | |
| 2727 | +540202,桑珠孜区,5402 | |
| 2728 | +540221,南木林县,5402 | |
| 2729 | +540222,江孜县,5402 | |
| 2730 | +540223,定日县,5402 | |
| 2731 | +540224,萨迦县,5402 | |
| 2732 | +540225,拉孜县,5402 | |
| 2733 | +540226,昂仁县,5402 | |
| 2734 | +540227,谢通门县,5402 | |
| 2735 | +540228,白朗县,5402 | |
| 2736 | +540229,仁布县,5402 | |
| 2737 | +540230,康马县,5402 | |
| 2738 | +540231,定结县,5402 | |
| 2739 | +540232,仲巴县,5402 | |
| 2740 | +540233,亚东县,5402 | |
| 2741 | +540234,吉隆县,5402 | |
| 2742 | +540235,聂拉木县,5402 | |
| 2743 | +540236,萨嘎县,5402 | |
| 2744 | +540237,岗巴县,5402 | |
| 2745 | +5403,昌都市,54 | |
| 2746 | +540302,卡若区,5403 | |
| 2747 | +540321,江达县,5403 | |
| 2748 | +540322,贡觉县,5403 | |
| 2749 | +540323,类乌齐县,5403 | |
| 2750 | +540324,丁青县,5403 | |
| 2751 | +540325,察雅县,5403 | |
| 2752 | +540326,八宿县,5403 | |
| 2753 | +540327,左贡县,5403 | |
| 2754 | +540328,芒康县,5403 | |
| 2755 | +540329,洛隆县,5403 | |
| 2756 | +540330,边坝县,5403 | |
| 2757 | +5404,林芝市,54 | |
| 2758 | +540402,巴宜区,5404 | |
| 2759 | +540421,工布江达县,5404 | |
| 2760 | +540422,米林县,5404 | |
| 2761 | +540423,墨脱县,5404 | |
| 2762 | +540424,波密县,5404 | |
| 2763 | +540425,察隅县,5404 | |
| 2764 | +540426,朗县,5404 | |
| 2765 | +5405,山南市,54 | |
| 2766 | +540502,乃东区,5405 | |
| 2767 | +540521,扎囊县,5405 | |
| 2768 | +540522,贡嘎县,5405 | |
| 2769 | +540523,桑日县,5405 | |
| 2770 | +540524,琼结县,5405 | |
| 2771 | +540525,曲松县,5405 | |
| 2772 | +540526,措美县,5405 | |
| 2773 | +540527,洛扎县,5405 | |
| 2774 | +540528,加查县,5405 | |
| 2775 | +540529,隆子县,5405 | |
| 2776 | +540530,错那县,5405 | |
| 2777 | +540531,浪卡子县,5405 | |
| 2778 | +5406,那曲市,54 | |
| 2779 | +540602,色尼区,5406 | |
| 2780 | +540621,嘉黎县,5406 | |
| 2781 | +540622,比如县,5406 | |
| 2782 | +540623,聂荣县,5406 | |
| 2783 | +540624,安多县,5406 | |
| 2784 | +540625,申扎县,5406 | |
| 2785 | +540626,索县,5406 | |
| 2786 | +540627,班戈县,5406 | |
| 2787 | +540628,巴青县,5406 | |
| 2788 | +540629,尼玛县,5406 | |
| 2789 | +540630,双湖县,5406 | |
| 2790 | +5425,阿里地区,54 | |
| 2791 | +542521,普兰县,5425 | |
| 2792 | +542522,札达县,5425 | |
| 2793 | +542523,噶尔县,5425 | |
| 2794 | +542524,日土县,5425 | |
| 2795 | +542525,革吉县,5425 | |
| 2796 | +542526,改则县,5425 | |
| 2797 | +542527,措勤县,5425 | |
| 2798 | +61,陕西省, | |
| 2799 | +6101,西安市,61 | |
| 2800 | +610102,新城区,6101 | |
| 2801 | +610103,碑林区,6101 | |
| 2802 | +610104,莲湖区,6101 | |
| 2803 | +610111,灞桥区,6101 | |
| 2804 | +610112,未央区,6101 | |
| 2805 | +610113,雁塔区,6101 | |
| 2806 | +610114,阎良区,6101 | |
| 2807 | +610115,临潼区,6101 | |
| 2808 | +610116,长安区,6101 | |
| 2809 | +610117,高陵区,6101 | |
| 2810 | +610118,鄠邑区,6101 | |
| 2811 | +610122,蓝田县,6101 | |
| 2812 | +610124,周至县,6101 | |
| 2813 | +6102,铜川市,61 | |
| 2814 | +610202,王益区,6102 | |
| 2815 | +610203,印台区,6102 | |
| 2816 | +610204,耀州区,6102 | |
| 2817 | +610222,宜君县,6102 | |
| 2818 | +6103,宝鸡市,61 | |
| 2819 | +610302,渭滨区,6103 | |
| 2820 | +610303,金台区,6103 | |
| 2821 | +610304,陈仓区,6103 | |
| 2822 | +610322,凤翔县,6103 | |
| 2823 | +610323,岐山县,6103 | |
| 2824 | +610324,扶风县,6103 | |
| 2825 | +610326,眉县,6103 | |
| 2826 | +610327,陇县,6103 | |
| 2827 | +610328,千阳县,6103 | |
| 2828 | +610329,麟游县,6103 | |
| 2829 | +610330,凤县,6103 | |
| 2830 | +610331,太白县,6103 | |
| 2831 | +6104,咸阳市,61 | |
| 2832 | +610402,秦都区,6104 | |
| 2833 | +610403,杨陵区,6104 | |
| 2834 | +610404,渭城区,6104 | |
| 2835 | +610422,三原县,6104 | |
| 2836 | +610423,泾阳县,6104 | |
| 2837 | +610424,乾县,6104 | |
| 2838 | +610425,礼泉县,6104 | |
| 2839 | +610426,永寿县,6104 | |
| 2840 | +610428,长武县,6104 | |
| 2841 | +610429,旬邑县,6104 | |
| 2842 | +610430,淳化县,6104 | |
| 2843 | +610431,武功县,6104 | |
| 2844 | +610481,兴平市,6104 | |
| 2845 | +610482,彬州市,6104 | |
| 2846 | +6105,渭南市,61 | |
| 2847 | +610502,临渭区,6105 | |
| 2848 | +610503,华州区,6105 | |
| 2849 | +610522,潼关县,6105 | |
| 2850 | +610523,大荔县,6105 | |
| 2851 | +610524,合阳县,6105 | |
| 2852 | +610525,澄城县,6105 | |
| 2853 | +610526,蒲城县,6105 | |
| 2854 | +610527,白水县,6105 | |
| 2855 | +610528,富平县,6105 | |
| 2856 | +610581,韩城市,6105 | |
| 2857 | +610582,华阴市,6105 | |
| 2858 | +6106,延安市,61 | |
| 2859 | +610602,宝塔区,6106 | |
| 2860 | +610603,安塞区,6106 | |
| 2861 | +610621,延长县,6106 | |
| 2862 | +610622,延川县,6106 | |
| 2863 | +610623,子长县,6106 | |
| 2864 | +610625,志丹县,6106 | |
| 2865 | +610626,吴起县,6106 | |
| 2866 | +610627,甘泉县,6106 | |
| 2867 | +610628,富县,6106 | |
| 2868 | +610629,洛川县,6106 | |
| 2869 | +610630,宜川县,6106 | |
| 2870 | +610631,黄龙县,6106 | |
| 2871 | +610632,黄陵县,6106 | |
| 2872 | +6107,汉中市,61 | |
| 2873 | +610702,汉台区,6107 | |
| 2874 | +610703,南郑区,6107 | |
| 2875 | +610722,城固县,6107 | |
| 2876 | +610723,洋县,6107 | |
| 2877 | +610724,西乡县,6107 | |
| 2878 | +610725,勉县,6107 | |
| 2879 | +610726,宁强县,6107 | |
| 2880 | +610727,略阳县,6107 | |
| 2881 | +610728,镇巴县,6107 | |
| 2882 | +610729,留坝县,6107 | |
| 2883 | +610730,佛坪县,6107 | |
| 2884 | +6108,榆林市,61 | |
| 2885 | +610802,榆阳区,6108 | |
| 2886 | +610803,横山区,6108 | |
| 2887 | +610822,府谷县,6108 | |
| 2888 | +610824,靖边县,6108 | |
| 2889 | +610825,定边县,6108 | |
| 2890 | +610826,绥德县,6108 | |
| 2891 | +610827,米脂县,6108 | |
| 2892 | +610828,佳县,6108 | |
| 2893 | +610829,吴堡县,6108 | |
| 2894 | +610830,清涧县,6108 | |
| 2895 | +610831,子洲县,6108 | |
| 2896 | +610881,神木市,6108 | |
| 2897 | +6109,安康市,61 | |
| 2898 | +610902,汉滨区,6109 | |
| 2899 | +610921,汉阴县,6109 | |
| 2900 | +610922,石泉县,6109 | |
| 2901 | +610923,宁陕县,6109 | |
| 2902 | +610924,紫阳县,6109 | |
| 2903 | +610925,岚皋县,6109 | |
| 2904 | +610926,平利县,6109 | |
| 2905 | +610927,镇坪县,6109 | |
| 2906 | +610928,旬阳县,6109 | |
| 2907 | +610929,白河县,6109 | |
| 2908 | +6110,商洛市,61 | |
| 2909 | +611002,商州区,6110 | |
| 2910 | +611021,洛南县,6110 | |
| 2911 | +611022,丹凤县,6110 | |
| 2912 | +611023,商南县,6110 | |
| 2913 | +611024,山阳县,6110 | |
| 2914 | +611025,镇安县,6110 | |
| 2915 | +611026,柞水县,6110 | |
| 2916 | +62,甘肃省, | |
| 2917 | +6201,兰州市,62 | |
| 2918 | +620102,城关区,6201 | |
| 2919 | +620103,七里河区,6201 | |
| 2920 | +620104,西固区,6201 | |
| 2921 | +620105,安宁区,6201 | |
| 2922 | +620111,红古区,6201 | |
| 2923 | +620121,永登县,6201 | |
| 2924 | +620122,皋兰县,6201 | |
| 2925 | +620123,榆中县,6201 | |
| 2926 | +6202,嘉峪关市,62 | |
| 2927 | +6203,金昌市,62 | |
| 2928 | +620302,金川区,6203 | |
| 2929 | +620321,永昌县,6203 | |
| 2930 | +6204,白银市,62 | |
| 2931 | +620402,白银区,6204 | |
| 2932 | +620403,平川区,6204 | |
| 2933 | +620421,靖远县,6204 | |
| 2934 | +620422,会宁县,6204 | |
| 2935 | +620423,景泰县,6204 | |
| 2936 | +6205,天水市,62 | |
| 2937 | +620502,秦州区,6205 | |
| 2938 | +620503,麦积区,6205 | |
| 2939 | +620521,清水县,6205 | |
| 2940 | +620522,秦安县,6205 | |
| 2941 | +620523,甘谷县,6205 | |
| 2942 | +620524,武山县,6205 | |
| 2943 | +620525,张家川回族自治县,6205 | |
| 2944 | +6206,武威市,62 | |
| 2945 | +620602,凉州区,6206 | |
| 2946 | +620621,民勤县,6206 | |
| 2947 | +620622,古浪县,6206 | |
| 2948 | +620623,天祝藏族自治县,6206 | |
| 2949 | +6207,张掖市,62 | |
| 2950 | +620702,甘州区,6207 | |
| 2951 | +620721,肃南裕固族自治县,6207 | |
| 2952 | +620722,民乐县,6207 | |
| 2953 | +620723,临泽县,6207 | |
| 2954 | +620724,高台县,6207 | |
| 2955 | +620725,山丹县,6207 | |
| 2956 | +6208,平凉市,62 | |
| 2957 | +620802,崆峒区,6208 | |
| 2958 | +620821,泾川县,6208 | |
| 2959 | +620822,灵台县,6208 | |
| 2960 | +620823,崇信县,6208 | |
| 2961 | +620825,庄浪县,6208 | |
| 2962 | +620826,静宁县,6208 | |
| 2963 | +620881,华亭市,6208 | |
| 2964 | +6209,酒泉市,62 | |
| 2965 | +620902,肃州区,6209 | |
| 2966 | +620921,金塔县,6209 | |
| 2967 | +620922,瓜州县,6209 | |
| 2968 | +620923,肃北蒙古族自治县,6209 | |
| 2969 | +620924,阿克塞哈萨克族自治县,6209 | |
| 2970 | +620981,玉门市,6209 | |
| 2971 | +620982,敦煌市,6209 | |
| 2972 | +6210,庆阳市,62 | |
| 2973 | +621002,西峰区,6210 | |
| 2974 | +621021,庆城县,6210 | |
| 2975 | +621022,环县,6210 | |
| 2976 | +621023,华池县,6210 | |
| 2977 | +621024,合水县,6210 | |
| 2978 | +621025,正宁县,6210 | |
| 2979 | +621026,宁县,6210 | |
| 2980 | +621027,镇原县,6210 | |
| 2981 | +6211,定西市,62 | |
| 2982 | +621102,安定区,6211 | |
| 2983 | +621121,通渭县,6211 | |
| 2984 | +621122,陇西县,6211 | |
| 2985 | +621123,渭源县,6211 | |
| 2986 | +621124,临洮县,6211 | |
| 2987 | +621125,漳县,6211 | |
| 2988 | +621126,岷县,6211 | |
| 2989 | +6212,陇南市,62 | |
| 2990 | +621202,武都区,6212 | |
| 2991 | +621221,成县,6212 | |
| 2992 | +621222,文县,6212 | |
| 2993 | +621223,宕昌县,6212 | |
| 2994 | +621224,康县,6212 | |
| 2995 | +621225,西和县,6212 | |
| 2996 | +621226,礼县,6212 | |
| 2997 | +621227,徽县,6212 | |
| 2998 | +621228,两当县,6212 | |
| 2999 | +6229,临夏回族自治州,62 | |
| 3000 | +622901,临夏市,6229 | |
| 3001 | +622921,临夏县,6229 | |
| 3002 | +622922,康乐县,6229 | |
| 3003 | +622923,永靖县,6229 | |
| 3004 | +622924,广河县,6229 | |
| 3005 | +622925,和政县,6229 | |
| 3006 | +622926,东乡族自治县,6229 | |
| 3007 | +622927,积石山保安族东乡族撒拉族自治县,6229 | |
| 3008 | +6230,甘南藏族自治州,62 | |
| 3009 | +623001,合作市,6230 | |
| 3010 | +623021,临潭县,6230 | |
| 3011 | +623022,卓尼县,6230 | |
| 3012 | +623023,舟曲县,6230 | |
| 3013 | +623024,迭部县,6230 | |
| 3014 | +623025,玛曲县,6230 | |
| 3015 | +623026,碌曲县,6230 | |
| 3016 | +623027,夏河县,6230 | |
| 3017 | +63,青海省, | |
| 3018 | +6301,西宁市,63 | |
| 3019 | +630102,城东区,6301 | |
| 3020 | +630103,城中区,6301 | |
| 3021 | +630104,城西区,6301 | |
| 3022 | +630105,城北区,6301 | |
| 3023 | +630121,大通回族土族自治县,6301 | |
| 3024 | +630122,湟中县,6301 | |
| 3025 | +630123,湟源县,6301 | |
| 3026 | +6302,海东市,63 | |
| 3027 | +630202,乐都区,6302 | |
| 3028 | +630203,平安区,6302 | |
| 3029 | +630222,民和回族土族自治县,6302 | |
| 3030 | +630223,互助土族自治县,6302 | |
| 3031 | +630224,化隆回族自治县,6302 | |
| 3032 | +630225,循化撒拉族自治县,6302 | |
| 3033 | +6322,海北藏族自治州,63 | |
| 3034 | +632221,门源回族自治县,6322 | |
| 3035 | +632222,祁连县,6322 | |
| 3036 | +632223,海晏县,6322 | |
| 3037 | +632224,刚察县,6322 | |
| 3038 | +6323,黄南藏族自治州,63 | |
| 3039 | +632321,同仁县,6323 | |
| 3040 | +632322,尖扎县,6323 | |
| 3041 | +632323,泽库县,6323 | |
| 3042 | +632324,河南蒙古族自治县,6323 | |
| 3043 | +6325,海南藏族自治州,63 | |
| 3044 | +632521,共和县,6325 | |
| 3045 | +632522,同德县,6325 | |
| 3046 | +632523,贵德县,6325 | |
| 3047 | +632524,兴海县,6325 | |
| 3048 | +632525,贵南县,6325 | |
| 3049 | +6326,果洛藏族自治州,63 | |
| 3050 | +632621,玛沁县,6326 | |
| 3051 | +632622,班玛县,6326 | |
| 3052 | +632623,甘德县,6326 | |
| 3053 | +632624,达日县,6326 | |
| 3054 | +632625,久治县,6326 | |
| 3055 | +632626,玛多县,6326 | |
| 3056 | +6327,玉树藏族自治州,63 | |
| 3057 | +632701,玉树市,6327 | |
| 3058 | +632722,杂多县,6327 | |
| 3059 | +632723,称多县,6327 | |
| 3060 | +632724,治多县,6327 | |
| 3061 | +632725,囊谦县,6327 | |
| 3062 | +632726,曲麻莱县,6327 | |
| 3063 | +6328,海西蒙古族藏族自治州,63 | |
| 3064 | +632801,格尔木市,6328 | |
| 3065 | +632802,德令哈市,6328 | |
| 3066 | +632803,茫崖市,6328 | |
| 3067 | +632821,乌兰县,6328 | |
| 3068 | +632822,都兰县,6328 | |
| 3069 | +632823,天峻县,6328 | |
| 3070 | +64,宁夏回族自治区, | |
| 3071 | +6401,银川市,64 | |
| 3072 | +640104,兴庆区,6401 | |
| 3073 | +640105,西夏区,6401 | |
| 3074 | +640106,金凤区,6401 | |
| 3075 | +640121,永宁县,6401 | |
| 3076 | +640122,贺兰县,6401 | |
| 3077 | +640181,灵武市,6401 | |
| 3078 | +6402,石嘴山市,64 | |
| 3079 | +640202,大武口区,6402 | |
| 3080 | +640205,惠农区,6402 | |
| 3081 | +640221,平罗县,6402 | |
| 3082 | +6403,吴忠市,64 | |
| 3083 | +640302,利通区,6403 | |
| 3084 | +640303,红寺堡区,6403 | |
| 3085 | +640323,盐池县,6403 | |
| 3086 | +640324,同心县,6403 | |
| 3087 | +640381,青铜峡市,6403 | |
| 3088 | +6404,固原市,64 | |
| 3089 | +640402,原州区,6404 | |
| 3090 | +640422,西吉县,6404 | |
| 3091 | +640423,隆德县,6404 | |
| 3092 | +640424,泾源县,6404 | |
| 3093 | +640425,彭阳县,6404 | |
| 3094 | +6405,中卫市,64 | |
| 3095 | +640502,沙坡头区,6405 | |
| 3096 | +640521,中宁县,6405 | |
| 3097 | +640522,海原县,6405 | |
| 3098 | +65,新疆维吾尔自治区, | |
| 3099 | +6501,乌鲁木齐市,65 | |
| 3100 | +650102,天山区,6501 | |
| 3101 | +650103,沙依巴克区,6501 | |
| 3102 | +650104,新市区,6501 | |
| 3103 | +650105,水磨沟区,6501 | |
| 3104 | +650106,头屯河区,6501 | |
| 3105 | +650107,达坂城区,6501 | |
| 3106 | +650109,米东区,6501 | |
| 3107 | +650121,乌鲁木齐县,6501 | |
| 3108 | +6502,克拉玛依市,65 | |
| 3109 | +650202,独山子区,6502 | |
| 3110 | +650203,克拉玛依区,6502 | |
| 3111 | +650204,白碱滩区,6502 | |
| 3112 | +650205,乌尔禾区,6502 | |
| 3113 | +6504,吐鲁番市,65 | |
| 3114 | +650402,高昌区,6504 | |
| 3115 | +650421,鄯善县,6504 | |
| 3116 | +650422,托克逊县,6504 | |
| 3117 | +6505,哈密市,65 | |
| 3118 | +650502,伊州区,6505 | |
| 3119 | +650521,巴里坤哈萨克自治县,6505 | |
| 3120 | +650522,伊吾县,6505 | |
| 3121 | +6523,昌吉回族自治州,65 | |
| 3122 | +652301,昌吉市,6523 | |
| 3123 | +652302,阜康市,6523 | |
| 3124 | +652323,呼图壁县,6523 | |
| 3125 | +652324,玛纳斯县,6523 | |
| 3126 | +652325,奇台县,6523 | |
| 3127 | +652327,吉木萨尔县,6523 | |
| 3128 | +652328,木垒哈萨克自治县,6523 | |
| 3129 | +6527,博尔塔拉蒙古自治州,65 | |
| 3130 | +652701,博乐市,6527 | |
| 3131 | +652702,阿拉山口市,6527 | |
| 3132 | +652722,精河县,6527 | |
| 3133 | +652723,温泉县,6527 | |
| 3134 | +6528,巴音郭楞蒙古自治州,65 | |
| 3135 | +652801,库尔勒市,6528 | |
| 3136 | +652822,轮台县,6528 | |
| 3137 | +652823,尉犁县,6528 | |
| 3138 | +652824,若羌县,6528 | |
| 3139 | +652825,且末县,6528 | |
| 3140 | +652826,焉耆回族自治县,6528 | |
| 3141 | +652827,和静县,6528 | |
| 3142 | +652828,和硕县,6528 | |
| 3143 | +652829,博湖县,6528 | |
| 3144 | +6529,阿克苏地区,65 | |
| 3145 | +652901,阿克苏市,6529 | |
| 3146 | +652922,温宿县,6529 | |
| 3147 | +652923,库车县,6529 | |
| 3148 | +652924,沙雅县,6529 | |
| 3149 | +652925,新和县,6529 | |
| 3150 | +652926,拜城县,6529 | |
| 3151 | +652927,乌什县,6529 | |
| 3152 | +652928,阿瓦提县,6529 | |
| 3153 | +652929,柯坪县,6529 | |
| 3154 | +6530,克孜勒苏柯尔克孜自治州,65 | |
| 3155 | +653001,阿图什市,6530 | |
| 3156 | +653022,阿克陶县,6530 | |
| 3157 | +653023,阿合奇县,6530 | |
| 3158 | +653024,乌恰县,6530 | |
| 3159 | +6531,喀什地区,65 | |
| 3160 | +653101,喀什市,6531 | |
| 3161 | +653121,疏附县,6531 | |
| 3162 | +653122,疏勒县,6531 | |
| 3163 | +653123,英吉沙县,6531 | |
| 3164 | +653124,泽普县,6531 | |
| 3165 | +653125,莎车县,6531 | |
| 3166 | +653126,叶城县,6531 | |
| 3167 | +653127,麦盖提县,6531 | |
| 3168 | +653128,岳普湖县,6531 | |
| 3169 | +653129,伽师县,6531 | |
| 3170 | +653130,巴楚县,6531 | |
| 3171 | +653131,塔什库尔干塔吉克自治县,6531 | |
| 3172 | +6532,和田地区,65 | |
| 3173 | +653201,和田市,6532 | |
| 3174 | +653221,和田县,6532 | |
| 3175 | +653222,墨玉县,6532 | |
| 3176 | +653223,皮山县,6532 | |
| 3177 | +653224,洛浦县,6532 | |
| 3178 | +653225,策勒县,6532 | |
| 3179 | +653226,于田县,6532 | |
| 3180 | +653227,民丰县,6532 | |
| 3181 | +6540,伊犁哈萨克自治州,65 | |
| 3182 | +654002,伊宁市,6540 | |
| 3183 | +654003,奎屯市,6540 | |
| 3184 | +654004,霍尔果斯市,6540 | |
| 3185 | +654021,伊宁县,6540 | |
| 3186 | +654022,察布查尔锡伯自治县,6540 | |
| 3187 | +654023,霍城县,6540 | |
| 3188 | +654024,巩留县,6540 | |
| 3189 | +654025,新源县,6540 | |
| 3190 | +654026,昭苏县,6540 | |
| 3191 | +654027,特克斯县,6540 | |
| 3192 | +654028,尼勒克县,6540 | |
| 3193 | +6542,塔城地区,65 | |
| 3194 | +654201,塔城市,6542 | |
| 3195 | +654202,乌苏市,6542 | |
| 3196 | +654221,额敏县,6542 | |
| 3197 | +654223,沙湾县,6542 | |
| 3198 | +654224,托里县,6542 | |
| 3199 | +654225,裕民县,6542 | |
| 3200 | +654226,和布克赛尔蒙古自治县,6542 | |
| 3201 | +6543,阿勒泰地区,65 | |
| 3202 | +654301,阿勒泰市,6543 | |
| 3203 | +654321,布尔津县,6543 | |
| 3204 | +654322,富蕴县,6543 | |
| 3205 | +654323,福海县,6543 | |
| 3206 | +654324,哈巴河县,6543 | |
| 3207 | +654325,青河县,6543 | |
| 3208 | +654326,吉木乃县,6543 | |
| 3209 | +659001,石河子市,65 | |
| 3210 | +659002,阿拉尔市,65 | |
| 3211 | +659003,图木舒克市,65 | |
| 3212 | +659004,五家渠市,65 | |
| 3213 | +659005,北屯市,65 | |
| 3214 | +659006,铁门关市,65 | |
| 3215 | +659007,双河市,65 | |
| 3216 | +659008,可克达拉市,65 | |
| 3217 | +659009,昆玉市,65 | |
| 3218 | +71,台湾省, | |
| 3219 | +81,香港特别行政区, | |
| 3220 | +82,澳门特别行政区, | |
| 0 | 3221 | \ No newline at end of file | ... | ... |
web_src/package-lock.json
| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | "name": "gb_web", |
| 9 | 9 | "version": "1.0.0", |
| 10 | 10 | "dependencies": { |
| 11 | - "@liveqing/liveplayer": "^2.7.0", | |
| 11 | + "@liveqing/liveplayer": "^2.7.10", | |
| 12 | 12 | "axios": "^0.24.0", |
| 13 | 13 | "core-js": "^2.6.5", |
| 14 | 14 | "echarts": "^4.9.0", |
| ... | ... | @@ -71,9 +71,9 @@ |
| 71 | 71 | } |
| 72 | 72 | }, |
| 73 | 73 | "node_modules/@liveqing/liveplayer": { |
| 74 | - "version": "2.7.0", | |
| 75 | - "resolved": "https://registry.npmmirror.com/@liveqing/liveplayer/-/liveplayer-2.7.0.tgz", | |
| 76 | - "integrity": "sha512-SWveQRqhhfJzkcpmHZxL6eLn+xLQuub888/JiBtUDHgt1eVwYYsorDiGcAKciNcyD70PuMfQ3+QrLoLbWE2vWA==" | |
| 74 | + "version": "2.7.10", | |
| 75 | + "resolved": "https://registry.npmmirror.com/@liveqing/liveplayer/-/liveplayer-2.7.10.tgz", | |
| 76 | + "integrity": "sha512-OrRzy2t0WZvO/h+hxMYL2+Ips7ON75l+PH8rjZDT7sps1zKW6dct6qPJm3EsVQuttUQ0dVGu3UXaSUm5gEM4dQ==" | |
| 77 | 77 | }, |
| 78 | 78 | "node_modules/@mapbox/jsonlint-lines-primitives": { |
| 79 | 79 | "version": "2.0.2", |
| ... | ... | @@ -184,15 +184,19 @@ |
| 184 | 184 | } |
| 185 | 185 | }, |
| 186 | 186 | "node_modules/ajv": { |
| 187 | - "version": "5.5.2", | |
| 188 | - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-5.5.2.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-5.5.2.tgz", | |
| 189 | - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", | |
| 187 | + "version": "6.12.6", | |
| 188 | + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", | |
| 189 | + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", | |
| 190 | 190 | "dev": true, |
| 191 | 191 | "dependencies": { |
| 192 | - "co": "^4.6.0", | |
| 193 | - "fast-deep-equal": "^1.0.0", | |
| 192 | + "fast-deep-equal": "^3.1.1", | |
| 194 | 193 | "fast-json-stable-stringify": "^2.0.0", |
| 195 | - "json-schema-traverse": "^0.3.0" | |
| 194 | + "json-schema-traverse": "^0.4.1", | |
| 195 | + "uri-js": "^4.2.2" | |
| 196 | + }, | |
| 197 | + "funding": { | |
| 198 | + "type": "github", | |
| 199 | + "url": "https://github.com/sponsors/epoberezkin" | |
| 196 | 200 | } |
| 197 | 201 | }, |
| 198 | 202 | "node_modules/ajv-keywords": { |
| ... | ... | @@ -2111,8 +2115,8 @@ |
| 2111 | 2115 | }, |
| 2112 | 2116 | "node_modules/co": { |
| 2113 | 2117 | "version": "4.6.0", |
| 2114 | - "resolved": "https://registry.npm.taobao.org/co/download/co-4.6.0.tgz", | |
| 2115 | - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", | |
| 2118 | + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", | |
| 2119 | + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", | |
| 2116 | 2120 | "dev": true, |
| 2117 | 2121 | "engines": { |
| 2118 | 2122 | "iojs": ">= 1.0.0", |
| ... | ... | @@ -4620,9 +4624,9 @@ |
| 4620 | 4624 | } |
| 4621 | 4625 | }, |
| 4622 | 4626 | "node_modules/fast-deep-equal": { |
| 4623 | - "version": "1.1.0", | |
| 4624 | - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-1.1.0.tgz", | |
| 4625 | - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", | |
| 4627 | + "version": "3.1.3", | |
| 4628 | + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", | |
| 4629 | + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", | |
| 4626 | 4630 | "dev": true |
| 4627 | 4631 | }, |
| 4628 | 4632 | "node_modules/fast-json-stable-stringify": { |
| ... | ... | @@ -4665,30 +4669,6 @@ |
| 4665 | 4669 | "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0" |
| 4666 | 4670 | } |
| 4667 | 4671 | }, |
| 4668 | - "node_modules/file-loader/node_modules/ajv": { | |
| 4669 | - "version": "6.12.5", | |
| 4670 | - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz", | |
| 4671 | - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=", | |
| 4672 | - "dev": true, | |
| 4673 | - "dependencies": { | |
| 4674 | - "fast-deep-equal": "^3.1.1", | |
| 4675 | - "fast-json-stable-stringify": "^2.0.0", | |
| 4676 | - "json-schema-traverse": "^0.4.1", | |
| 4677 | - "uri-js": "^4.2.2" | |
| 4678 | - } | |
| 4679 | - }, | |
| 4680 | - "node_modules/file-loader/node_modules/fast-deep-equal": { | |
| 4681 | - "version": "3.1.3", | |
| 4682 | - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz", | |
| 4683 | - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", | |
| 4684 | - "dev": true | |
| 4685 | - }, | |
| 4686 | - "node_modules/file-loader/node_modules/json-schema-traverse": { | |
| 4687 | - "version": "0.4.1", | |
| 4688 | - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz", | |
| 4689 | - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", | |
| 4690 | - "dev": true | |
| 4691 | - }, | |
| 4692 | 4672 | "node_modules/file-loader/node_modules/schema-utils": { |
| 4693 | 4673 | "version": "0.4.7", |
| 4694 | 4674 | "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-0.4.7.tgz?cache=0&sync_timestamp=1601922251376&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-0.4.7.tgz", |
| ... | ... | @@ -6126,9 +6106,9 @@ |
| 6126 | 6106 | "dev": true |
| 6127 | 6107 | }, |
| 6128 | 6108 | "node_modules/json-schema-traverse": { |
| 6129 | - "version": "0.3.1", | |
| 6130 | - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.3.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.3.1.tgz", | |
| 6131 | - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", | |
| 6109 | + "version": "0.4.1", | |
| 6110 | + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", | |
| 6111 | + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", | |
| 6132 | 6112 | "dev": true |
| 6133 | 6113 | }, |
| 6134 | 6114 | "node_modules/json-stringify-pretty-compact": { |
| ... | ... | @@ -8770,30 +8750,6 @@ |
| 8770 | 8750 | "node": ">= 4" |
| 8771 | 8751 | } |
| 8772 | 8752 | }, |
| 8773 | - "node_modules/postcss-loader/node_modules/ajv": { | |
| 8774 | - "version": "6.12.5", | |
| 8775 | - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz", | |
| 8776 | - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=", | |
| 8777 | - "dev": true, | |
| 8778 | - "dependencies": { | |
| 8779 | - "fast-deep-equal": "^3.1.1", | |
| 8780 | - "fast-json-stable-stringify": "^2.0.0", | |
| 8781 | - "json-schema-traverse": "^0.4.1", | |
| 8782 | - "uri-js": "^4.2.2" | |
| 8783 | - } | |
| 8784 | - }, | |
| 8785 | - "node_modules/postcss-loader/node_modules/fast-deep-equal": { | |
| 8786 | - "version": "3.1.3", | |
| 8787 | - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz", | |
| 8788 | - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", | |
| 8789 | - "dev": true | |
| 8790 | - }, | |
| 8791 | - "node_modules/postcss-loader/node_modules/json-schema-traverse": { | |
| 8792 | - "version": "0.4.1", | |
| 8793 | - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz", | |
| 8794 | - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", | |
| 8795 | - "dev": true | |
| 8796 | - }, | |
| 8797 | 8753 | "node_modules/postcss-loader/node_modules/schema-utils": { |
| 8798 | 8754 | "version": "0.4.7", |
| 8799 | 8755 | "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-0.4.7.tgz?cache=0&sync_timestamp=1601922251376&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-0.4.7.tgz", |
| ... | ... | @@ -11500,6 +11456,30 @@ |
| 11500 | 11456 | "node": ">= 4.3 < 5.0.0 || >= 5.10" |
| 11501 | 11457 | } |
| 11502 | 11458 | }, |
| 11459 | + "node_modules/schema-utils/node_modules/ajv": { | |
| 11460 | + "version": "5.5.2", | |
| 11461 | + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", | |
| 11462 | + "integrity": "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw==", | |
| 11463 | + "dev": true, | |
| 11464 | + "dependencies": { | |
| 11465 | + "co": "^4.6.0", | |
| 11466 | + "fast-deep-equal": "^1.0.0", | |
| 11467 | + "fast-json-stable-stringify": "^2.0.0", | |
| 11468 | + "json-schema-traverse": "^0.3.0" | |
| 11469 | + } | |
| 11470 | + }, | |
| 11471 | + "node_modules/schema-utils/node_modules/fast-deep-equal": { | |
| 11472 | + "version": "1.1.0", | |
| 11473 | + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", | |
| 11474 | + "integrity": "sha512-fueX787WZKCV0Is4/T2cyAdM4+x1S3MXXOAhavE1ys/W42SHAPacLTQhucja22QBYrfGw50M2sRiXPtTGv9Ymw==", | |
| 11475 | + "dev": true | |
| 11476 | + }, | |
| 11477 | + "node_modules/schema-utils/node_modules/json-schema-traverse": { | |
| 11478 | + "version": "0.3.1", | |
| 11479 | + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", | |
| 11480 | + "integrity": "sha512-4JD/Ivzg7PoW8NzdrBSr3UFwC9mHgvI7Z6z3QGBsSHgKaRTUDmyZAAKJo2UbG1kUVfS9WS8bi36N49U1xw43DA==", | |
| 11481 | + "dev": true | |
| 11482 | + }, | |
| 11503 | 11483 | "node_modules/select": { |
| 11504 | 11484 | "version": "1.1.2", |
| 11505 | 11485 | "resolved": "https://registry.npm.taobao.org/select/download/select-1.1.2.tgz", |
| ... | ... | @@ -12721,36 +12701,12 @@ |
| 12721 | 12701 | "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0" |
| 12722 | 12702 | } |
| 12723 | 12703 | }, |
| 12724 | - "node_modules/uglifyjs-webpack-plugin/node_modules/ajv": { | |
| 12725 | - "version": "6.12.5", | |
| 12726 | - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz", | |
| 12727 | - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=", | |
| 12728 | - "dev": true, | |
| 12729 | - "dependencies": { | |
| 12730 | - "fast-deep-equal": "^3.1.1", | |
| 12731 | - "fast-json-stable-stringify": "^2.0.0", | |
| 12732 | - "json-schema-traverse": "^0.4.1", | |
| 12733 | - "uri-js": "^4.2.2" | |
| 12734 | - } | |
| 12735 | - }, | |
| 12736 | 12704 | "node_modules/uglifyjs-webpack-plugin/node_modules/commander": { |
| 12737 | 12705 | "version": "2.13.0", |
| 12738 | 12706 | "resolved": "https://registry.npm.taobao.org/commander/download/commander-2.13.0.tgz?cache=0&sync_timestamp=1598576136669&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.13.0.tgz", |
| 12739 | 12707 | "integrity": "sha1-aWS8pnaF33wfFDDFhPB9dZeIW5w=", |
| 12740 | 12708 | "dev": true |
| 12741 | 12709 | }, |
| 12742 | - "node_modules/uglifyjs-webpack-plugin/node_modules/fast-deep-equal": { | |
| 12743 | - "version": "3.1.3", | |
| 12744 | - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz", | |
| 12745 | - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", | |
| 12746 | - "dev": true | |
| 12747 | - }, | |
| 12748 | - "node_modules/uglifyjs-webpack-plugin/node_modules/json-schema-traverse": { | |
| 12749 | - "version": "0.4.1", | |
| 12750 | - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz", | |
| 12751 | - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", | |
| 12752 | - "dev": true | |
| 12753 | - }, | |
| 12754 | 12710 | "node_modules/uglifyjs-webpack-plugin/node_modules/schema-utils": { |
| 12755 | 12711 | "version": "0.4.7", |
| 12756 | 12712 | "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-0.4.7.tgz?cache=0&sync_timestamp=1601922251376&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-0.4.7.tgz", |
| ... | ... | @@ -14082,24 +14038,6 @@ |
| 14082 | 14038 | "source-map": "~0.6.1" |
| 14083 | 14039 | } |
| 14084 | 14040 | }, |
| 14085 | - "node_modules/webpack/node_modules/ajv": { | |
| 14086 | - "version": "6.12.5", | |
| 14087 | - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz", | |
| 14088 | - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=", | |
| 14089 | - "dev": true, | |
| 14090 | - "dependencies": { | |
| 14091 | - "fast-deep-equal": "^3.1.1", | |
| 14092 | - "fast-json-stable-stringify": "^2.0.0", | |
| 14093 | - "json-schema-traverse": "^0.4.1", | |
| 14094 | - "uri-js": "^4.2.2" | |
| 14095 | - } | |
| 14096 | - }, | |
| 14097 | - "node_modules/webpack/node_modules/fast-deep-equal": { | |
| 14098 | - "version": "3.1.3", | |
| 14099 | - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz", | |
| 14100 | - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", | |
| 14101 | - "dev": true | |
| 14102 | - }, | |
| 14103 | 14041 | "node_modules/webpack/node_modules/has-flag": { |
| 14104 | 14042 | "version": "2.0.0", |
| 14105 | 14043 | "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-2.0.0.tgz", |
| ... | ... | @@ -14109,12 +14047,6 @@ |
| 14109 | 14047 | "node": ">=0.10.0" |
| 14110 | 14048 | } |
| 14111 | 14049 | }, |
| 14112 | - "node_modules/webpack/node_modules/json-schema-traverse": { | |
| 14113 | - "version": "0.4.1", | |
| 14114 | - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz", | |
| 14115 | - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", | |
| 14116 | - "dev": true | |
| 14117 | - }, | |
| 14118 | 14050 | "node_modules/webpack/node_modules/source-map": { |
| 14119 | 14051 | "version": "0.5.7", |
| 14120 | 14052 | "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", |
| ... | ... | @@ -14464,9 +14396,9 @@ |
| 14464 | 14396 | }, |
| 14465 | 14397 | "dependencies": { |
| 14466 | 14398 | "@liveqing/liveplayer": { |
| 14467 | - "version": "2.7.0", | |
| 14468 | - "resolved": "https://registry.npmmirror.com/@liveqing/liveplayer/-/liveplayer-2.7.0.tgz", | |
| 14469 | - "integrity": "sha512-SWveQRqhhfJzkcpmHZxL6eLn+xLQuub888/JiBtUDHgt1eVwYYsorDiGcAKciNcyD70PuMfQ3+QrLoLbWE2vWA==" | |
| 14399 | + "version": "2.7.10", | |
| 14400 | + "resolved": "https://registry.npmmirror.com/@liveqing/liveplayer/-/liveplayer-2.7.10.tgz", | |
| 14401 | + "integrity": "sha512-OrRzy2t0WZvO/h+hxMYL2+Ips7ON75l+PH8rjZDT7sps1zKW6dct6qPJm3EsVQuttUQ0dVGu3UXaSUm5gEM4dQ==" | |
| 14470 | 14402 | }, |
| 14471 | 14403 | "@mapbox/jsonlint-lines-primitives": { |
| 14472 | 14404 | "version": "2.0.2", |
| ... | ... | @@ -14551,15 +14483,15 @@ |
| 14551 | 14483 | } |
| 14552 | 14484 | }, |
| 14553 | 14485 | "ajv": { |
| 14554 | - "version": "5.5.2", | |
| 14555 | - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-5.5.2.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-5.5.2.tgz", | |
| 14556 | - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", | |
| 14486 | + "version": "6.12.6", | |
| 14487 | + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", | |
| 14488 | + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", | |
| 14557 | 14489 | "dev": true, |
| 14558 | 14490 | "requires": { |
| 14559 | - "co": "^4.6.0", | |
| 14560 | - "fast-deep-equal": "^1.0.0", | |
| 14491 | + "fast-deep-equal": "^3.1.1", | |
| 14561 | 14492 | "fast-json-stable-stringify": "^2.0.0", |
| 14562 | - "json-schema-traverse": "^0.3.0" | |
| 14493 | + "json-schema-traverse": "^0.4.1", | |
| 14494 | + "uri-js": "^4.2.2" | |
| 14563 | 14495 | } |
| 14564 | 14496 | }, |
| 14565 | 14497 | "ajv-keywords": { |
| ... | ... | @@ -16303,8 +16235,8 @@ |
| 16303 | 16235 | }, |
| 16304 | 16236 | "co": { |
| 16305 | 16237 | "version": "4.6.0", |
| 16306 | - "resolved": "https://registry.npm.taobao.org/co/download/co-4.6.0.tgz", | |
| 16307 | - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", | |
| 16238 | + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", | |
| 16239 | + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", | |
| 16308 | 16240 | "dev": true |
| 16309 | 16241 | }, |
| 16310 | 16242 | "coa": { |
| ... | ... | @@ -18423,9 +18355,9 @@ |
| 18423 | 18355 | } |
| 18424 | 18356 | }, |
| 18425 | 18357 | "fast-deep-equal": { |
| 18426 | - "version": "1.1.0", | |
| 18427 | - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-1.1.0.tgz", | |
| 18428 | - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", | |
| 18358 | + "version": "3.1.3", | |
| 18359 | + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", | |
| 18360 | + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", | |
| 18429 | 18361 | "dev": true |
| 18430 | 18362 | }, |
| 18431 | 18363 | "fast-json-stable-stringify": { |
| ... | ... | @@ -18459,30 +18391,6 @@ |
| 18459 | 18391 | "schema-utils": "^0.4.5" |
| 18460 | 18392 | }, |
| 18461 | 18393 | "dependencies": { |
| 18462 | - "ajv": { | |
| 18463 | - "version": "6.12.5", | |
| 18464 | - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz", | |
| 18465 | - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=", | |
| 18466 | - "dev": true, | |
| 18467 | - "requires": { | |
| 18468 | - "fast-deep-equal": "^3.1.1", | |
| 18469 | - "fast-json-stable-stringify": "^2.0.0", | |
| 18470 | - "json-schema-traverse": "^0.4.1", | |
| 18471 | - "uri-js": "^4.2.2" | |
| 18472 | - } | |
| 18473 | - }, | |
| 18474 | - "fast-deep-equal": { | |
| 18475 | - "version": "3.1.3", | |
| 18476 | - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz", | |
| 18477 | - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", | |
| 18478 | - "dev": true | |
| 18479 | - }, | |
| 18480 | - "json-schema-traverse": { | |
| 18481 | - "version": "0.4.1", | |
| 18482 | - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz", | |
| 18483 | - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", | |
| 18484 | - "dev": true | |
| 18485 | - }, | |
| 18486 | 18394 | "schema-utils": { |
| 18487 | 18395 | "version": "0.4.7", |
| 18488 | 18396 | "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-0.4.7.tgz?cache=0&sync_timestamp=1601922251376&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-0.4.7.tgz", |
| ... | ... | @@ -19648,9 +19556,9 @@ |
| 19648 | 19556 | "dev": true |
| 19649 | 19557 | }, |
| 19650 | 19558 | "json-schema-traverse": { |
| 19651 | - "version": "0.3.1", | |
| 19652 | - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.3.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.3.1.tgz", | |
| 19653 | - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", | |
| 19559 | + "version": "0.4.1", | |
| 19560 | + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", | |
| 19561 | + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", | |
| 19654 | 19562 | "dev": true |
| 19655 | 19563 | }, |
| 19656 | 19564 | "json-stringify-pretty-compact": { |
| ... | ... | @@ -21822,30 +21730,6 @@ |
| 21822 | 21730 | "schema-utils": "^0.4.0" |
| 21823 | 21731 | }, |
| 21824 | 21732 | "dependencies": { |
| 21825 | - "ajv": { | |
| 21826 | - "version": "6.12.5", | |
| 21827 | - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz", | |
| 21828 | - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=", | |
| 21829 | - "dev": true, | |
| 21830 | - "requires": { | |
| 21831 | - "fast-deep-equal": "^3.1.1", | |
| 21832 | - "fast-json-stable-stringify": "^2.0.0", | |
| 21833 | - "json-schema-traverse": "^0.4.1", | |
| 21834 | - "uri-js": "^4.2.2" | |
| 21835 | - } | |
| 21836 | - }, | |
| 21837 | - "fast-deep-equal": { | |
| 21838 | - "version": "3.1.3", | |
| 21839 | - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz", | |
| 21840 | - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", | |
| 21841 | - "dev": true | |
| 21842 | - }, | |
| 21843 | - "json-schema-traverse": { | |
| 21844 | - "version": "0.4.1", | |
| 21845 | - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz", | |
| 21846 | - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", | |
| 21847 | - "dev": true | |
| 21848 | - }, | |
| 21849 | 21733 | "schema-utils": { |
| 21850 | 21734 | "version": "0.4.7", |
| 21851 | 21735 | "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-0.4.7.tgz?cache=0&sync_timestamp=1601922251376&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-0.4.7.tgz", |
| ... | ... | @@ -24097,6 +23981,32 @@ |
| 24097 | 23981 | "dev": true, |
| 24098 | 23982 | "requires": { |
| 24099 | 23983 | "ajv": "^5.0.0" |
| 23984 | + }, | |
| 23985 | + "dependencies": { | |
| 23986 | + "ajv": { | |
| 23987 | + "version": "5.5.2", | |
| 23988 | + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", | |
| 23989 | + "integrity": "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw==", | |
| 23990 | + "dev": true, | |
| 23991 | + "requires": { | |
| 23992 | + "co": "^4.6.0", | |
| 23993 | + "fast-deep-equal": "^1.0.0", | |
| 23994 | + "fast-json-stable-stringify": "^2.0.0", | |
| 23995 | + "json-schema-traverse": "^0.3.0" | |
| 23996 | + } | |
| 23997 | + }, | |
| 23998 | + "fast-deep-equal": { | |
| 23999 | + "version": "1.1.0", | |
| 24000 | + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", | |
| 24001 | + "integrity": "sha512-fueX787WZKCV0Is4/T2cyAdM4+x1S3MXXOAhavE1ys/W42SHAPacLTQhucja22QBYrfGw50M2sRiXPtTGv9Ymw==", | |
| 24002 | + "dev": true | |
| 24003 | + }, | |
| 24004 | + "json-schema-traverse": { | |
| 24005 | + "version": "0.3.1", | |
| 24006 | + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", | |
| 24007 | + "integrity": "sha512-4JD/Ivzg7PoW8NzdrBSr3UFwC9mHgvI7Z6z3QGBsSHgKaRTUDmyZAAKJo2UbG1kUVfS9WS8bi36N49U1xw43DA==", | |
| 24008 | + "dev": true | |
| 24009 | + } | |
| 24100 | 24010 | } |
| 24101 | 24011 | }, |
| 24102 | 24012 | "select": { |
| ... | ... | @@ -25116,36 +25026,12 @@ |
| 25116 | 25026 | "worker-farm": "^1.5.2" |
| 25117 | 25027 | }, |
| 25118 | 25028 | "dependencies": { |
| 25119 | - "ajv": { | |
| 25120 | - "version": "6.12.5", | |
| 25121 | - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz", | |
| 25122 | - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=", | |
| 25123 | - "dev": true, | |
| 25124 | - "requires": { | |
| 25125 | - "fast-deep-equal": "^3.1.1", | |
| 25126 | - "fast-json-stable-stringify": "^2.0.0", | |
| 25127 | - "json-schema-traverse": "^0.4.1", | |
| 25128 | - "uri-js": "^4.2.2" | |
| 25129 | - } | |
| 25130 | - }, | |
| 25131 | 25029 | "commander": { |
| 25132 | 25030 | "version": "2.13.0", |
| 25133 | 25031 | "resolved": "https://registry.npm.taobao.org/commander/download/commander-2.13.0.tgz?cache=0&sync_timestamp=1598576136669&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.13.0.tgz", |
| 25134 | 25032 | "integrity": "sha1-aWS8pnaF33wfFDDFhPB9dZeIW5w=", |
| 25135 | 25033 | "dev": true |
| 25136 | 25034 | }, |
| 25137 | - "fast-deep-equal": { | |
| 25138 | - "version": "3.1.3", | |
| 25139 | - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz", | |
| 25140 | - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", | |
| 25141 | - "dev": true | |
| 25142 | - }, | |
| 25143 | - "json-schema-traverse": { | |
| 25144 | - "version": "0.4.1", | |
| 25145 | - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz", | |
| 25146 | - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", | |
| 25147 | - "dev": true | |
| 25148 | - }, | |
| 25149 | 25035 | "schema-utils": { |
| 25150 | 25036 | "version": "0.4.7", |
| 25151 | 25037 | "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-0.4.7.tgz?cache=0&sync_timestamp=1601922251376&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-0.4.7.tgz", |
| ... | ... | @@ -25846,36 +25732,12 @@ |
| 25846 | 25732 | "yargs": "^8.0.2" |
| 25847 | 25733 | }, |
| 25848 | 25734 | "dependencies": { |
| 25849 | - "ajv": { | |
| 25850 | - "version": "6.12.5", | |
| 25851 | - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz", | |
| 25852 | - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=", | |
| 25853 | - "dev": true, | |
| 25854 | - "requires": { | |
| 25855 | - "fast-deep-equal": "^3.1.1", | |
| 25856 | - "fast-json-stable-stringify": "^2.0.0", | |
| 25857 | - "json-schema-traverse": "^0.4.1", | |
| 25858 | - "uri-js": "^4.2.2" | |
| 25859 | - } | |
| 25860 | - }, | |
| 25861 | - "fast-deep-equal": { | |
| 25862 | - "version": "3.1.3", | |
| 25863 | - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz", | |
| 25864 | - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", | |
| 25865 | - "dev": true | |
| 25866 | - }, | |
| 25867 | 25735 | "has-flag": { |
| 25868 | 25736 | "version": "2.0.0", |
| 25869 | 25737 | "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-2.0.0.tgz", |
| 25870 | 25738 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", |
| 25871 | 25739 | "dev": true |
| 25872 | 25740 | }, |
| 25873 | - "json-schema-traverse": { | |
| 25874 | - "version": "0.4.1", | |
| 25875 | - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz", | |
| 25876 | - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", | |
| 25877 | - "dev": true | |
| 25878 | - }, | |
| 25879 | 25741 | "source-map": { |
| 25880 | 25742 | "version": "0.5.7", |
| 25881 | 25743 | "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", | ... | ... |
web_src/package.json
web_src/src/components/DeviceList.vue
| ... | ... | @@ -41,8 +41,8 @@ |
| 41 | 41 | <el-table-column label="状态" min-width="120"> |
| 42 | 42 | <template slot-scope="scope"> |
| 43 | 43 | <div slot="reference" class="name-wrapper"> |
| 44 | - <el-tag size="medium" v-if="scope.row.online == 1">在线</el-tag> | |
| 45 | - <el-tag size="medium" type="info" v-if="scope.row.online == 0">离线</el-tag> | |
| 44 | + <el-tag size="medium" v-if="scope.row.onLine">在线</el-tag> | |
| 45 | + <el-tag size="medium" type="info" v-if="!scope.row.onLine">离线</el-tag> | |
| 46 | 46 | </div> |
| 47 | 47 | </template> |
| 48 | 48 | </el-table-column> | ... | ... |
web_src/src/components/ParentPlatformList.vue
| ... | ... | @@ -144,7 +144,7 @@ export default { |
| 144 | 144 | }, |
| 145 | 145 | chooseChannel: function(platform) { |
| 146 | 146 | console.log("platform.name: " + platform.name) |
| 147 | - this.$refs.chooseChannelDialog.openDialog(platform.serverGBId,platform.deviceGBId, platform.name, platform.catalogId, platform.treeType, this.initData) | |
| 147 | + this.$refs.chooseChannelDialog.openDialog(platform.serverGBId,platform.deviceGBId, platform.name, platform.catalogId, this.initData) | |
| 148 | 148 | }, |
| 149 | 149 | initData: function() { |
| 150 | 150 | this.getPlatformList(); | ... | ... |
web_src/src/components/StreamProxyList.vue
| ... | ... | @@ -22,8 +22,8 @@ |
| 22 | 22 | {{scope.row.url}} |
| 23 | 23 | </el-tag> |
| 24 | 24 | <el-tag size="medium" v-if="scope.row.type != 'default'"> |
| 25 | - <i class="cpoy-btn el-icon-document-copy" title="点击拷贝" v-clipboard="scope.row.src_url" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></i> | |
| 26 | - {{scope.row.src_url}} | |
| 25 | + <i class="cpoy-btn el-icon-document-copy" title="点击拷贝" v-clipboard="scope.row.srcUrl" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></i> | |
| 26 | + {{scope.row.srcUrl}} | |
| 27 | 27 | </el-tag> |
| 28 | 28 | </div> |
| 29 | 29 | </template> |
| ... | ... | @@ -58,25 +58,25 @@ |
| 58 | 58 | <el-table-column label="音频" min-width="120" > |
| 59 | 59 | <template slot-scope="scope"> |
| 60 | 60 | <div slot="reference" class="name-wrapper"> |
| 61 | - <el-tag size="medium" v-if="scope.row.enable_audio">已启用</el-tag> | |
| 62 | - <el-tag size="medium" type="info" v-if="!scope.row.enable_audio">未启用</el-tag> | |
| 61 | + <el-tag size="medium" v-if="scope.row.enableAudio">已启用</el-tag> | |
| 62 | + <el-tag size="medium" type="info" v-if="!scope.row.enableAudio">未启用</el-tag> | |
| 63 | 63 | </div> |
| 64 | 64 | </template> |
| 65 | 65 | </el-table-column> |
| 66 | 66 | <el-table-column label="录制" min-width="120" > |
| 67 | 67 | <template slot-scope="scope"> |
| 68 | 68 | <div slot="reference" class="name-wrapper"> |
| 69 | - <el-tag size="medium" v-if="scope.row.enable_mp4">已启用</el-tag> | |
| 70 | - <el-tag size="medium" type="info" v-if="!scope.row.enable_mp4">未启用</el-tag> | |
| 69 | + <el-tag size="medium" v-if="scope.row.enableMp4">已启用</el-tag> | |
| 70 | + <el-tag size="medium" type="info" v-if="!scope.row.enableMp4">未启用</el-tag> | |
| 71 | 71 | </div> |
| 72 | 72 | </template> |
| 73 | 73 | </el-table-column> |
| 74 | 74 | <el-table-column label="无人观看" min-width="160" > |
| 75 | 75 | <template slot-scope="scope"> |
| 76 | 76 | <div slot="reference" class="name-wrapper"> |
| 77 | - <el-tag size="medium" v-if="scope.row.enable_remove_none_reader">移除</el-tag> | |
| 78 | - <el-tag size="medium" v-if="scope.row.enable_disable_none_reader">停用</el-tag> | |
| 79 | - <el-tag size="medium" type="info" v-if="!scope.row.enable_remove_none_reader && !scope.row.enable_disable_none_reader">不做处理</el-tag> | |
| 77 | + <el-tag size="medium" v-if="scope.row.enableRemoveNoneReader">移除</el-tag> | |
| 78 | + <el-tag size="medium" v-if="scope.row.enableDisableNoneReader">停用</el-tag> | |
| 79 | + <el-tag size="medium" type="info" v-if="!scope.row.enableRemoveNoneReader && !scope.row.enableDisableNoneReader">不做处理</el-tag> | |
| 80 | 80 | </div> |
| 81 | 81 | </template> |
| 82 | 82 | </el-table-column> |
| ... | ... | @@ -197,7 +197,7 @@ |
| 197 | 197 | this.$refs.onvifEdit.openDialog(res.data.data, (url)=>{ |
| 198 | 198 | if (url != null) { |
| 199 | 199 | this.$refs.onvifEdit.close(); |
| 200 | - this.$refs.streamProxyEdit.openDialog({type: "default", url: url, src_url: url}, this.initData()) | |
| 200 | + this.$refs.streamProxyEdit.openDialog({type: "default", url: url, srcUrl: url}, this.initData()) | |
| 201 | 201 | } |
| 202 | 202 | }) |
| 203 | 203 | }else { |
| ... | ... | @@ -245,18 +245,25 @@ |
| 245 | 245 | }, |
| 246 | 246 | deleteStreamProxy: function(row){ |
| 247 | 247 | let that = this; |
| 248 | - that.$axios({ | |
| 249 | - method:"delete", | |
| 250 | - url:"/api/proxy/del", | |
| 251 | - params:{ | |
| 252 | - app: row.app, | |
| 253 | - stream: row.stream | |
| 254 | - } | |
| 255 | - }).then((res)=>{ | |
| 256 | - that.initData() | |
| 257 | - }).catch(function (error) { | |
| 258 | - console.log(error); | |
| 259 | - }); | |
| 248 | + this.$confirm('确定删除此代理吗?', '提示', { | |
| 249 | + confirmButtonText: '确定', | |
| 250 | + cancelButtonText: '取消', | |
| 251 | + type: 'warning' | |
| 252 | + }).then(() => { | |
| 253 | + that.$axios({ | |
| 254 | + method:"delete", | |
| 255 | + url:"/api/proxy/del", | |
| 256 | + params:{ | |
| 257 | + app: row.app, | |
| 258 | + stream: row.stream | |
| 259 | + } | |
| 260 | + }).then((res)=>{ | |
| 261 | + that.initData() | |
| 262 | + }).catch(function (error) { | |
| 263 | + console.log(error); | |
| 264 | + }); | |
| 265 | + }).catch(() => { | |
| 266 | + }); | |
| 260 | 267 | }, |
| 261 | 268 | start: function(row){ |
| 262 | 269 | this.stopUpdateList() | ... | ... |
web_src/src/components/channelList.vue
| ... | ... | @@ -26,6 +26,12 @@ |
| 26 | 26 | <el-option label="在线" value="true"></el-option> |
| 27 | 27 | <el-option label="离线" value="false"></el-option> |
| 28 | 28 | </el-select> |
| 29 | + 清晰度: | |
| 30 | + <el-select size="mini" style="margin-right: 1rem;" @change="search" v-model="isSubStream" placeholder="请选择" | |
| 31 | + default-first-option> | |
| 32 | + <el-option label="原画" :value="false"></el-option> | |
| 33 | + <el-option label="流畅" :value="true"></el-option> | |
| 34 | + </el-select> | |
| 29 | 35 | </div> |
| 30 | 36 | <el-button icon="el-icon-refresh-right" circle size="mini" @click="refresh()"></el-button> |
| 31 | 37 | <el-button v-if="showTree" icon="iconfont icon-list" circle size="mini" @click="switchList()"></el-button> |
| ... | ... | @@ -79,8 +85,8 @@ |
| 79 | 85 | <el-table-column label="状态" min-width="120"> |
| 80 | 86 | <template slot-scope="scope"> |
| 81 | 87 | <div slot="reference" class="name-wrapper"> |
| 82 | - <el-tag size="medium" v-if="scope.row.status === 1">在线</el-tag> | |
| 83 | - <el-tag size="medium" type="info" v-if="scope.row.status === 0">离线</el-tag> | |
| 88 | + <el-tag size="medium" v-if="scope.row.status === true">在线</el-tag> | |
| 89 | + <el-tag size="medium" type="info" v-if="scope.row.status === false">离线</el-tag> | |
| 84 | 90 | </div> |
| 85 | 91 | </template> |
| 86 | 92 | </el-table-column> |
| ... | ... | @@ -146,6 +152,7 @@ export default { |
| 146 | 152 | searchSrt: "", |
| 147 | 153 | channelType: "", |
| 148 | 154 | online: "", |
| 155 | + isSubStream: false, | |
| 149 | 156 | winHeight: window.innerHeight - 200, |
| 150 | 157 | currentPage: 1, |
| 151 | 158 | count: 15, |
| ... | ... | @@ -237,7 +244,10 @@ export default { |
| 237 | 244 | let that = this; |
| 238 | 245 | this.$axios({ |
| 239 | 246 | method: 'get', |
| 240 | - url: '/api/play/start/' + deviceId + '/' + channelId | |
| 247 | + url: '/api/play/start/' + deviceId + '/' + channelId, | |
| 248 | + params:{ | |
| 249 | + isSubStream: this.isSubStream | |
| 250 | + } | |
| 241 | 251 | }).then(function (res) { |
| 242 | 252 | console.log(res) |
| 243 | 253 | that.isLoging = false; |
| ... | ... | @@ -277,7 +287,10 @@ export default { |
| 277 | 287 | var that = this; |
| 278 | 288 | this.$axios({ |
| 279 | 289 | method: 'get', |
| 280 | - url: '/api/play/stop/' + this.deviceId + "/" + itemData.channelId | |
| 290 | + url: '/api/play/stop/' + this.deviceId + "/" + itemData.channelId, | |
| 291 | + params:{ | |
| 292 | + isSubStream: this.isSubStream | |
| 293 | + } | |
| 281 | 294 | }).then(function (res) { |
| 282 | 295 | that.initData(); |
| 283 | 296 | }).catch(function (error) { | ... | ... |
web_src/src/components/dialog/StreamProxyEdit.vue
| ... | ... | @@ -33,13 +33,13 @@ |
| 33 | 33 | <el-form-item label="拉流地址" prop="url" v-if="proxyParam.type=='default'"> |
| 34 | 34 | <el-input v-model="proxyParam.url" clearable></el-input> |
| 35 | 35 | </el-form-item> |
| 36 | - <el-form-item label="拉流地址" prop="src_url" v-if="proxyParam.type=='ffmpeg'"> | |
| 37 | - <el-input v-model="proxyParam.src_url" clearable></el-input> | |
| 36 | + <el-form-item label="拉流地址" prop="srcUrl" v-if="proxyParam.type=='ffmpeg'"> | |
| 37 | + <el-input v-model="proxyParam.srcUrl" clearable></el-input> | |
| 38 | 38 | </el-form-item> |
| 39 | - <el-form-item label="超时时间:毫秒" prop="timeout_ms" v-if="proxyParam.type=='ffmpeg'"> | |
| 40 | - <el-input v-model="proxyParam.timeout_ms" clearable></el-input> | |
| 39 | + <el-form-item label="超时时间:毫秒" prop="timeoutMs" v-if="proxyParam.type=='ffmpeg'"> | |
| 40 | + <el-input v-model="proxyParam.timeoutMs" clearable></el-input> | |
| 41 | 41 | </el-form-item> |
| 42 | - <el-form-item label="节点选择" prop="rtp_type"> | |
| 42 | + <el-form-item label="节点选择" prop="rtpType"> | |
| 43 | 43 | <el-select |
| 44 | 44 | v-model="proxyParam.mediaServerId" |
| 45 | 45 | @change="mediaServerIdChange" |
| ... | ... | @@ -54,10 +54,9 @@ |
| 54 | 54 | </el-option> |
| 55 | 55 | </el-select> |
| 56 | 56 | </el-form-item> |
| 57 | - <el-form-item label="FFmpeg命令模板" prop="ffmpeg_cmd_key" v-if="proxyParam.type=='ffmpeg'"> | |
| 58 | -<!-- <el-input v-model="proxyParam.ffmpeg_cmd_key" clearable></el-input>--> | |
| 57 | + <el-form-item label="FFmpeg命令模板" prop="ffmpegCmdKey" v-if="proxyParam.type=='ffmpeg'"> | |
| 59 | 58 | <el-select |
| 60 | - v-model="proxyParam.ffmpeg_cmd_key" | |
| 59 | + v-model="proxyParam.ffmpegCmdKey" | |
| 61 | 60 | style="width: 100%" |
| 62 | 61 | placeholder="请选择FFmpeg命令模板" |
| 63 | 62 | > |
| ... | ... | @@ -72,9 +71,9 @@ |
| 72 | 71 | <el-form-item label="国标编码" prop="gbId"> |
| 73 | 72 | <el-input v-model="proxyParam.gbId" placeholder="设置国标编码可推送到国标" clearable></el-input> |
| 74 | 73 | </el-form-item> |
| 75 | - <el-form-item label="拉流方式" prop="rtp_type" v-if="proxyParam.type=='default'"> | |
| 74 | + <el-form-item label="拉流方式" prop="rtpType" v-if="proxyParam.type=='default'"> | |
| 76 | 75 | <el-select |
| 77 | - v-model="proxyParam.rtp_type" | |
| 76 | + v-model="proxyParam.rtpType" | |
| 78 | 77 | style="width: 100%" |
| 79 | 78 | placeholder="请选择拉流方式" |
| 80 | 79 | > |
| ... | ... | @@ -83,10 +82,10 @@ |
| 83 | 82 | <el-option label="组播" value="2"></el-option> |
| 84 | 83 | </el-select> |
| 85 | 84 | </el-form-item> |
| 86 | - <el-form-item label="无人观看" prop="rtp_type" > | |
| 85 | + <el-form-item label="无人观看" prop="rtpType" > | |
| 87 | 86 | <el-select |
| 88 | 87 | @change="noneReaderHandler" |
| 89 | - v-model="proxyParam.none_reader" | |
| 88 | + v-model="proxyParam.noneReader" | |
| 90 | 89 | style="width: 100%" |
| 91 | 90 | placeholder="请选择无人观看的处理方式" |
| 92 | 91 | > |
| ... | ... | @@ -98,8 +97,8 @@ |
| 98 | 97 | <el-form-item label="其他选项"> |
| 99 | 98 | <div style="float: left;"> |
| 100 | 99 | <el-checkbox label="启用" v-model="proxyParam.enable" ></el-checkbox> |
| 101 | - <el-checkbox label="开启音频" v-model="proxyParam.enable_audio" ></el-checkbox> | |
| 102 | - <el-checkbox label="录制" v-model="proxyParam.enable_mp4" ></el-checkbox> | |
| 100 | + <el-checkbox label="开启音频" v-model="proxyParam.enableAudio" ></el-checkbox> | |
| 101 | + <el-checkbox label="录制" v-model="proxyParam.enableMp4" ></el-checkbox> | |
| 103 | 102 | </div> |
| 104 | 103 | |
| 105 | 104 | </el-form-item> |
| ... | ... | @@ -155,17 +154,17 @@ export default { |
| 155 | 154 | app: null, |
| 156 | 155 | stream: null, |
| 157 | 156 | url: "", |
| 158 | - src_url: null, | |
| 159 | - timeout_ms: null, | |
| 160 | - ffmpeg_cmd_key: null, | |
| 157 | + srcUrl: null, | |
| 158 | + timeoutMs: null, | |
| 159 | + ffmpegCmdKey: null, | |
| 161 | 160 | gbId: null, |
| 162 | - rtp_type: null, | |
| 161 | + rtpType: null, | |
| 163 | 162 | enable: true, |
| 164 | - enable_audio: true, | |
| 165 | - enable_mp4: false, | |
| 166 | - none_reader: null, | |
| 167 | - enable_remove_none_reader: false, | |
| 168 | - enable_disable_none_reader: false, | |
| 163 | + enableAudio: true, | |
| 164 | + enableMp4: false, | |
| 165 | + noneReader: null, | |
| 166 | + enableRemoveNoneReader: false, | |
| 167 | + enableDisableNoneReader: false, | |
| 169 | 168 | platformGbId: null, |
| 170 | 169 | mediaServerId: null, |
| 171 | 170 | }, |
| ... | ... | @@ -177,9 +176,9 @@ export default { |
| 177 | 176 | app: [{ required: true, message: "请输入应用名", trigger: "blur" }], |
| 178 | 177 | stream: [{ required: true, message: "请输入流ID", trigger: "blur" }], |
| 179 | 178 | url: [{ required: true, message: "请输入要代理的流", trigger: "blur" }], |
| 180 | - src_url: [{ required: true, message: "请输入要代理的流", trigger: "blur" }], | |
| 181 | - timeout_ms: [{ required: true, message: "请输入FFmpeg推流成功超时时间", trigger: "blur" }], | |
| 182 | - ffmpeg_cmd_key: [{ required: false, message: "请输入FFmpeg命令参数模板(可选)", trigger: "blur" }], | |
| 179 | + srcUrl: [{ required: true, message: "请输入要代理的流", trigger: "blur" }], | |
| 180 | + timeoutMs: [{ required: true, message: "请输入FFmpeg推流成功超时时间", trigger: "blur" }], | |
| 181 | + ffmpegCmdKey: [{ required: false, message: "请输入FFmpeg命令参数模板(可选)", trigger: "blur" }], | |
| 183 | 182 | }, |
| 184 | 183 | }; |
| 185 | 184 | }, |
| ... | ... | @@ -189,7 +188,7 @@ export default { |
| 189 | 188 | this.listChangeCallback = callback; |
| 190 | 189 | if (proxyParam != null) { |
| 191 | 190 | this.proxyParam = proxyParam; |
| 192 | - this.proxyParam.none_reader = null; | |
| 191 | + this.proxyParam.noneReader = null; | |
| 193 | 192 | } |
| 194 | 193 | |
| 195 | 194 | let that = this; |
| ... | ... | @@ -218,7 +217,7 @@ export default { |
| 218 | 217 | } |
| 219 | 218 | }).then(function (res) { |
| 220 | 219 | that.ffmpegCmdList = res.data.data; |
| 221 | - that.proxyParam.ffmpeg_cmd_key = Object.keys(res.data.data)[0]; | |
| 220 | + that.proxyParam.ffmpegCmdKey = Object.keys(res.data.data)[0]; | |
| 222 | 221 | }).catch(function (error) { |
| 223 | 222 | console.log(error); |
| 224 | 223 | }); |
| ... | ... | @@ -275,15 +274,15 @@ export default { |
| 275 | 274 | } |
| 276 | 275 | }, |
| 277 | 276 | noneReaderHandler: function() { |
| 278 | - if (this.proxyParam.none_reader === null || this.proxyParam.none_reader === "0") { | |
| 279 | - this.proxyParam.enable_disable_none_reader = false; | |
| 280 | - this.proxyParam.enable_remove_none_reader = false; | |
| 281 | - }else if (this.proxyParam.none_reader === "1"){ | |
| 282 | - this.proxyParam.enable_disable_none_reader = true; | |
| 283 | - this.proxyParam.enable_remove_none_reader = false; | |
| 284 | - }else if (this.proxyParam.none_reader ==="2"){ | |
| 285 | - this.proxyParam.enable_disable_none_reader = false; | |
| 286 | - this.proxyParam.enable_remove_none_reader = true; | |
| 277 | + if (this.proxyParam.noneReader === null || this.proxyParam.noneReader === "0") { | |
| 278 | + this.proxyParam.enableDisableNoneReader = false; | |
| 279 | + this.proxyParam.enableRemoveNoneReader = false; | |
| 280 | + }else if (this.proxyParam.noneReader === "1"){ | |
| 281 | + this.proxyParam.enableDisableNoneReader = true; | |
| 282 | + this.proxyParam.enableRemoveNoneReader = false; | |
| 283 | + }else if (this.proxyParam.noneReader ==="2"){ | |
| 284 | + this.proxyParam.enableDisableNoneReader = false; | |
| 285 | + this.proxyParam.enableRemoveNoneReader = true; | |
| 287 | 286 | } |
| 288 | 287 | }, |
| 289 | 288 | }, | ... | ... |
web_src/src/components/dialog/catalogEdit.vue
| ... | ... | @@ -46,12 +46,11 @@ |
| 46 | 46 | export default { |
| 47 | 47 | name: "catalogEdit", |
| 48 | 48 | computed: {}, |
| 49 | - props: ['platformId'], | |
| 49 | + props: ['platformId', 'platformDeviceId'], | |
| 50 | 50 | created() {}, |
| 51 | 51 | data() { |
| 52 | 52 | let checkId = (rule, value, callback) => { |
| 53 | 53 | console.log("checkId") |
| 54 | - console.log(this.treeType) | |
| 55 | 54 | console.log(rule) |
| 56 | 55 | console.log(value) |
| 57 | 56 | console.log(value.length) |
| ... | ... | @@ -59,21 +58,34 @@ export default { |
| 59 | 58 | if (!value) { |
| 60 | 59 | return callback(new Error('编号不能为空')); |
| 61 | 60 | } |
| 62 | - if (this.treeType === "BusinessGroup" && value.length !== 20) { | |
| 63 | - return callback(new Error('编号必须由20位数字组成')); | |
| 64 | - } | |
| 65 | - if (this.treeType === "CivilCode" && value.length <= 8 && value.length%2 !== 0) { | |
| 66 | - return callback(new Error('行政区划必须是八位以下的偶数个数字组成')); | |
| 67 | - } | |
| 68 | - if (this.treeType === "BusinessGroup") { | |
| 61 | + if (value.trim().length <= 8) { | |
| 62 | + if (value.trim().length%2 !== 0) { | |
| 63 | + return callback(new Error('行政区划编号必须为2/4/6/8位')); | |
| 64 | + } | |
| 65 | + if (this.form.parentId !== this.platformDeviceId && this.form.parentId.length >= value.trim().length) { | |
| 66 | + return callback(new Error('行政区划编号长度应该每次两位递增')); | |
| 67 | + } | |
| 68 | + }else { | |
| 69 | + if (value.trim().length !== 20) { | |
| 70 | + return callback(new Error('编号必须为2/4/6/8位的行政区划或20位的虚拟组织/业务分组')); | |
| 71 | + } | |
| 69 | 72 | let catalogType = value.substring(10, 13); |
| 70 | 73 | console.log(catalogType) |
| 71 | - // 216 为虚拟组织 215 为业务分组;目录第一级必须为业务分组, 业务分组下为虚拟组织,虚拟组织下可以有其他虚拟组织 | |
| 72 | - if (this.level === 1 && catalogType !== "215") { | |
| 73 | - return callback(new Error('业务分组模式下第一层目录的编号11到13位必须为215')); | |
| 74 | + if (catalogType !== "215" && catalogType !== "216") { | |
| 75 | + return callback(new Error('编号错误,业务分组11-13位为215,虚拟组织11-13位为216')); | |
| 74 | 76 | } |
| 75 | - if (this.level > 1 && catalogType !== "216") { | |
| 76 | - return callback(new Error('业务分组模式下第一层以下目录的编号11到13位必须为216')); | |
| 77 | + if (catalogType === "216") { | |
| 78 | + | |
| 79 | + if (this.form.parentId !== this.platformDeviceId){ | |
| 80 | + if (this.form.parentId.length <= 8) { | |
| 81 | + return callback(new Error('编号错误,建立虚拟组织前必须先建立业务分组(11-13位为215)')); | |
| 82 | + } | |
| 83 | + } | |
| 84 | + } | |
| 85 | + if (catalogType === "215") { | |
| 86 | + if (this.form.parentId.length === "215") { | |
| 87 | + return callback(new Error('编号错误,业务分组下只能建立虚拟组织(11-13位为216)')); | |
| 88 | + } | |
| 77 | 89 | } |
| 78 | 90 | } |
| 79 | 91 | callback(); |
| ... | ... | @@ -83,7 +95,6 @@ export default { |
| 83 | 95 | showDialog: false, |
| 84 | 96 | isLoging: false, |
| 85 | 97 | isEdit: false, |
| 86 | - treeType: null, | |
| 87 | 98 | level: 0, |
| 88 | 99 | form: { |
| 89 | 100 | id: null, |
| ... | ... | @@ -98,7 +109,7 @@ export default { |
| 98 | 109 | }; |
| 99 | 110 | }, |
| 100 | 111 | methods: { |
| 101 | - openDialog: function (isEdit, id, name, parentId, treeType, level, callback) { | |
| 112 | + openDialog: function (isEdit, id, name, parentId, level, callback) { | |
| 102 | 113 | console.log("parentId: " + parentId) |
| 103 | 114 | console.log(this.form) |
| 104 | 115 | this.isEdit = isEdit; |
| ... | ... | @@ -108,7 +119,6 @@ export default { |
| 108 | 119 | this.form.parentId = parentId; |
| 109 | 120 | this.showDialog = true; |
| 110 | 121 | this.submitCallback = callback; |
| 111 | - this.treeType = treeType; | |
| 112 | 122 | this.level = level; |
| 113 | 123 | }, |
| 114 | 124 | onSubmit: function () { | ... | ... |
web_src/src/components/dialog/chooseChannel.vue
| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | <el-tab-pane label="目录结构" name="catalog"> |
| 9 | 9 | <el-container> |
| 10 | 10 | <el-main v-bind:style="{backgroundColor: '#FFF', maxHeight: winHeight + 'px'}"> |
| 11 | - <chooseChannelForCatalog ref="chooseChannelForCatalog" :platformId=platformId :platformDeviceId=platformDeviceId :platformName=platformName :defaultCatalogId=defaultCatalogId :catalogIdChange="catalogIdChange" :treeType=treeType ></chooseChannelForCatalog> | |
| 11 | + <chooseChannelForCatalog ref="chooseChannelForCatalog" :platformId=platformId :platformDeviceId=platformDeviceId :platformName=platformName :defaultCatalogId=defaultCatalogId :catalogIdChange="catalogIdChange" ></chooseChannelForCatalog> | |
| 12 | 12 | </el-main> |
| 13 | 13 | </el-container> |
| 14 | 14 | </el-tab-pane> |
| ... | ... | @@ -67,14 +67,13 @@ export default { |
| 67 | 67 | platformName: "", |
| 68 | 68 | defaultCatalogId: "", |
| 69 | 69 | showDialog: false, |
| 70 | - treeType: null, | |
| 71 | 70 | chooseData: {}, |
| 72 | 71 | winHeight: window.innerHeight - 250, |
| 73 | 72 | |
| 74 | 73 | }; |
| 75 | 74 | }, |
| 76 | 75 | methods: { |
| 77 | - openDialog(platformId, platformDeviceId, platformName, defaultCatalogId, treeType, closeCallback) { | |
| 76 | + openDialog(platformId, platformDeviceId, platformName, defaultCatalogId, closeCallback) { | |
| 78 | 77 | console.log("defaultCatalogId: " + defaultCatalogId) |
| 79 | 78 | this.platformId = platformId |
| 80 | 79 | this.platformDeviceId = platformDeviceId |
| ... | ... | @@ -82,7 +81,6 @@ export default { |
| 82 | 81 | this.defaultCatalogId = defaultCatalogId |
| 83 | 82 | this.showDialog = true |
| 84 | 83 | this.closeCallback = closeCallback |
| 85 | - this.treeType = treeType | |
| 86 | 84 | }, |
| 87 | 85 | tabClick (tab, event){ |
| 88 | 86 | ... | ... |
web_src/src/components/dialog/chooseChannelForCatalog.vue
| ... | ... | @@ -28,7 +28,7 @@ |
| 28 | 28 | </span> |
| 29 | 29 | </el-tree> |
| 30 | 30 | </div> |
| 31 | - <catalogEdit ref="catalogEdit" :platformId="platformId"></catalogEdit> | |
| 31 | + <catalogEdit ref="catalogEdit" :platformId="platformId" :platformDeviceId="platformDeviceId"></catalogEdit> | |
| 32 | 32 | </div> |
| 33 | 33 | </template> |
| 34 | 34 | |
| ... | ... | @@ -38,7 +38,7 @@ |
| 38 | 38 | import catalogEdit from './catalogEdit.vue' |
| 39 | 39 | export default { |
| 40 | 40 | name: 'chooseChannelForCatalog', |
| 41 | - props: ['platformId', 'platformDeviceId', 'platformName', 'defaultCatalogId', 'catalogIdChange', 'treeType'], | |
| 41 | + props: ['platformId', 'platformDeviceId', 'platformName', 'defaultCatalogId', 'catalogIdChange'], | |
| 42 | 42 | created() { |
| 43 | 43 | this.chooseId = this.defaultCatalogId; |
| 44 | 44 | this.defaultCatalogIdSign = this.defaultCatalogId; |
| ... | ... | @@ -101,9 +101,10 @@ export default { |
| 101 | 101 | }, |
| 102 | 102 | addCatalog: function (parentId, node){ |
| 103 | 103 | let that = this; |
| 104 | - console.log(this.treeType) | |
| 104 | + console.log(this.platformId) | |
| 105 | + console.log(parentId) | |
| 105 | 106 | // 打开添加弹窗 |
| 106 | - that.$refs.catalogEdit.openDialog(false, null, null, parentId, this.treeType, node.level, ()=>{ | |
| 107 | + that.$refs.catalogEdit.openDialog(false, null, null, parentId, node.level, ()=>{ | |
| 107 | 108 | node.loaded = false |
| 108 | 109 | node.expand(); |
| 109 | 110 | }); | ... | ... |
web_src/src/components/dialog/deviceEdit.vue
| ... | ... | @@ -52,12 +52,6 @@ |
| 52 | 52 | <el-option key="GCJ02" label="GCJ02" value="GCJ02"></el-option> |
| 53 | 53 | </el-select> |
| 54 | 54 | </el-form-item> |
| 55 | - <el-form-item label="目录结构" prop="treeType" > | |
| 56 | - <el-select v-model="form.treeType" style="float: left; width: 100%" > | |
| 57 | - <el-option key="WGS84" label="行政区划" value="CivilCode"></el-option> | |
| 58 | - <el-option key="GCJ02" label="业务分组" value="BusinessGroup"></el-option> | |
| 59 | - </el-select> | |
| 60 | - </el-form-item> | |
| 61 | 55 | <el-form-item v-if="this.isEdit" label="目录订阅" title="0为取消订阅" prop="subscribeCycleForCatalog" > |
| 62 | 56 | <el-input v-model="form.subscribeCycleForCatalog" clearable ></el-input> |
| 63 | 57 | </el-form-item> |
| ... | ... | @@ -67,6 +61,12 @@ |
| 67 | 61 | <el-form-item v-if="form.subscribeCycleForMobilePosition > 0" label="移动位置报送间隔" prop="subscribeCycleForCatalog" > |
| 68 | 62 | <el-input v-model="form.mobilePositionSubmissionInterval" clearable ></el-input> |
| 69 | 63 | </el-form-item> |
| 64 | + <el-form-item label="主子码流开关" prop="switchPrimarySubStream" > | |
| 65 | + <el-select v-model="form.switchPrimarySubStream" style="float: left; width: 100%" > | |
| 66 | + <el-option key="true" label="开启" :value="true"></el-option> | |
| 67 | + <el-option key="false" label="关闭" :value="false"></el-option> | |
| 68 | + </el-select> | |
| 69 | + </el-form-item> | |
| 70 | 70 | <el-form-item label="其他选项"> |
| 71 | 71 | <el-checkbox label="SSRC校验" v-model="form.ssrcCheck" style="float: left"></el-checkbox> |
| 72 | 72 | <el-checkbox label="作为消息通道" v-model="form.asMessageChannel" style="float: left"></el-checkbox> | ... | ... |
web_src/src/components/dialog/devicePlayer.vue
| ... | ... | @@ -16,7 +16,6 @@ |
| 16 | 16 | :hasAudio="hasAudio" fluent autoplay live></rtc-player> |
| 17 | 17 | </el-tab-pane> |
| 18 | 18 | <el-tab-pane label="h265web">h265web敬请期待</el-tab-pane> |
| 19 | - <el-tab-pane label="wsPlayer">wsPlayer 敬请期待</el-tab-pane> | |
| 20 | 19 | </el-tabs> |
| 21 | 20 | <jessibucaPlayer v-if="Object.keys(this.player).length == 1 && this.player.jessibuca" ref="jessibuca" |
| 22 | 21 | :visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError" |
| ... | ... | @@ -540,25 +539,31 @@ export default { |
| 540 | 539 | // if (callback )callback(); |
| 541 | 540 | }, |
| 542 | 541 | |
| 543 | - playFromStreamInfo: function (realHasAudio, streamInfo) { | |
| 544 | - this.showVideoDialog = true; | |
| 545 | - this.hasaudio = realHasAudio && this.hasaudio; | |
| 546 | - this.$refs[this.activePlayer].play(this.getUrlByStreamInfo(streamInfo)) | |
| 547 | - }, | |
| 548 | - close: function () { | |
| 549 | - console.log('关闭视频'); | |
| 550 | - if (!!this.$refs[this.activePlayer]) { | |
| 551 | - this.$refs[this.activePlayer].pause(); | |
| 552 | - } | |
| 553 | - this.videoUrl = ''; | |
| 554 | - this.coverPlaying = false; | |
| 555 | - this.showVideoDialog = false; | |
| 556 | - if (this.convertKey != '') { | |
| 557 | - this.convertStop(); | |
| 558 | - } | |
| 559 | - this.convertKey = '' | |
| 560 | - this.stopBroadcast() | |
| 561 | - }, | |
| 542 | + playFromStreamInfo: function (realHasAudio, streamInfo) { | |
| 543 | + this.showVideoDialog = true; | |
| 544 | + this.hasaudio = realHasAudio && this.hasaudio; | |
| 545 | + if (this.$refs[this.activePlayer]) { | |
| 546 | + this.$refs[this.activePlayer].play(this.getUrlByStreamInfo(streamInfo)) | |
| 547 | + }else { | |
| 548 | + this.$nextTick(() => { | |
| 549 | + this.$refs[this.activePlayer].play(this.getUrlByStreamInfo(streamInfo)) | |
| 550 | + }); | |
| 551 | + } | |
| 552 | + }, | |
| 553 | + close: function () { | |
| 554 | + console.log('关闭视频'); | |
| 555 | + if (!!this.$refs[this.activePlayer]){ | |
| 556 | + this.$refs[this.activePlayer].pause(); | |
| 557 | + } | |
| 558 | + this.videoUrl = ''; | |
| 559 | + this.coverPlaying = false; | |
| 560 | + this.showVideoDialog = false; | |
| 561 | + if (this.convertKey != '') { | |
| 562 | + this.convertStop(); | |
| 563 | + } | |
| 564 | + this.convertKey = '' | |
| 565 | + this.stopBroadcast() | |
| 566 | + }, | |
| 562 | 567 | |
| 563 | 568 | copySharedInfo: function (data) { |
| 564 | 569 | console.log('复制内容:' + data); | ... | ... |
web_src/src/components/dialog/platformEdit.vue
| ... | ... | @@ -78,12 +78,6 @@ |
| 78 | 78 | <el-option label="8" value="8"></el-option> |
| 79 | 79 | </el-select> |
| 80 | 80 | </el-form-item> |
| 81 | - <el-form-item label="目录结构" prop="treeType" > | |
| 82 | - <el-select v-model="platform.treeType" style="width: 100%" @change="treeTypeChange"> | |
| 83 | - <el-option key="WGS84" label="行政区划" value="CivilCode"></el-option> | |
| 84 | - <el-option key="GCJ02" label="业务分组" value="BusinessGroup"></el-option> | |
| 85 | - </el-select> | |
| 86 | - </el-form-item> | |
| 87 | 81 | <el-form-item label="字符集" prop="characterSet"> |
| 88 | 82 | <el-select |
| 89 | 83 | v-model="platform.characterSet" |
| ... | ... | @@ -164,7 +158,6 @@ export default { |
| 164 | 158 | startOfflinePush: false, |
| 165 | 159 | catalogGroup: 1, |
| 166 | 160 | administrativeDivision: null, |
| 167 | - treeType: "BusinessGroup", | |
| 168 | 161 | }, |
| 169 | 162 | rules: { |
| 170 | 163 | name: [{ required: true, message: "请输入平台名称", trigger: "blur" }], |
| ... | ... | @@ -203,7 +196,6 @@ export default { |
| 203 | 196 | that.platform.devicePort = res.data.data.devicePort; |
| 204 | 197 | that.platform.username = res.data.data.username; |
| 205 | 198 | that.platform.password = res.data.data.password; |
| 206 | - that.platform.treeType = "BusinessGroup"; | |
| 207 | 199 | that.platform.administrativeDivision = res.data.data.username.substr(0, 6); |
| 208 | 200 | } |
| 209 | 201 | |
| ... | ... | @@ -234,7 +226,6 @@ export default { |
| 234 | 226 | this.platform.startOfflinePush = platform.startOfflinePush; |
| 235 | 227 | this.platform.catalogGroup = platform.catalogGroup; |
| 236 | 228 | this.platform.administrativeDivision = platform.administrativeDivision; |
| 237 | - this.platform.treeType = platform.treeType; | |
| 238 | 229 | this.onSubmit_text = "保存"; |
| 239 | 230 | this.saveUrl = "/api/platform/save"; |
| 240 | 231 | } |
| ... | ... | @@ -252,7 +243,6 @@ export default { |
| 252 | 243 | if (this.platform.administrativeDivision == null) { |
| 253 | 244 | this.platform.administrativeDivision = this.platform.deviceGBId.substr(0, 6); |
| 254 | 245 | } |
| 255 | - | |
| 256 | 246 | }, |
| 257 | 247 | onSubmit: function () { |
| 258 | 248 | this.saveForm() |
| ... | ... | @@ -309,7 +299,6 @@ export default { |
| 309 | 299 | keepTimeout: 60, |
| 310 | 300 | transport: "UDP", |
| 311 | 301 | characterSet: "GB2312", |
| 312 | - treeType: "BusinessGroup", | |
| 313 | 302 | startOfflinePush: false, |
| 314 | 303 | catalogGroup: 1, |
| 315 | 304 | } |
| ... | ... | @@ -344,13 +333,6 @@ export default { |
| 344 | 333 | }); |
| 345 | 334 | } |
| 346 | 335 | }, |
| 347 | - treeTypeChange: function (){ | |
| 348 | - this.$message({ | |
| 349 | - showClose: true, | |
| 350 | - message: "修改目录结构会导致关联目录与通道数据被清空,保存后生效", | |
| 351 | - type: "warning", | |
| 352 | - }); | |
| 353 | - } | |
| 354 | 336 | }, |
| 355 | 337 | }; |
| 356 | 338 | </script> | ... | ... |
web_src/src/components/map.vue
| ... | ... | @@ -22,10 +22,10 @@ |
| 22 | 22 | <el-descriptions-item label="行政区域" >{{channel.civilCode}}</el-descriptions-item> |
| 23 | 23 | <el-descriptions-item label="设备归属" >{{channel.owner}}</el-descriptions-item> |
| 24 | 24 | <el-descriptions-item label="安装地址" >{{channel.address == null?'未知': channel.address}}</el-descriptions-item> |
| 25 | - <el-descriptions-item label="云台类型" >{{channel.ptztypeText}}</el-descriptions-item> | |
| 26 | - <el-descriptions-item label="状态"> | |
| 27 | - <el-tag size="small" v-if="channel.status === 1">在线</el-tag> | |
| 28 | - <el-tag size="small" type="info" v-if="channel.status === 0">离线</el-tag> | |
| 25 | + <el-descriptions-item label="云台类型" >{{channel.PTZTypeText}}</el-descriptions-item> | |
| 26 | + <el-descriptions-item label="通道状态"> | |
| 27 | + <el-tag size="small" v-if="channel.status === true">在线</el-tag> | |
| 28 | + <el-tag size="small" type="info" v-if="channel.status === false">离线</el-tag> | |
| 29 | 29 | </el-descriptions-item> |
| 30 | 30 | </el-descriptions> |
| 31 | 31 | <div style="padding-top: 10px"> | ... | ... |