Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fd160e1a2 | ||
|
|
97a0d940eb | ||
|
|
efaa099d81 | ||
|
|
47864a804b | ||
|
|
91136c0e43 | ||
|
|
28c3b1bd61 | ||
|
|
551352bc40 | ||
|
|
e73c24c925 | ||
|
|
7ec4c286cc | ||
|
|
6705e2ec4b | ||
|
|
6f0373063b | ||
|
|
f64eef60b5 | ||
|
|
89546bf86b | ||
|
|
793678feca | ||
|
|
923cc3019a | ||
|
|
10eb98a5f6 | ||
|
|
bd9e89d8dd | ||
|
|
1926b4ce73 | ||
|
|
4ef3062d74 | ||
|
|
abb6e0f60f | ||
|
|
f204d8d84e | ||
|
|
fa301656f1 | ||
|
|
7e1221028f | ||
|
|
41308cb2dd | ||
|
|
130600521c | ||
|
|
cd57548a48 | ||
|
|
efacc99f76 | ||
|
|
f0d236e172 | ||
|
|
a8118bd8c6 | ||
|
|
0e58f2ef53 | ||
|
|
f4b22b3a0c |
BIN
Image/gitLogo.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
25
README.md
@@ -1,5 +1,7 @@
|
||||
<div align="center"><h1 align="center">ThingsGateway</a></h1></div>
|
||||
<div align="center"><h3 align="center">边缘采集网关</h3></div>
|
||||
|
||||
<div align='center'>
|
||||
<img src="https://gitee.com/diego2098/ThingsGateway/raw/master/Image/gitLogo.png" height=100 />
|
||||
</div>
|
||||
|
||||
#### 介绍
|
||||
|
||||
@@ -15,6 +17,13 @@
|
||||
- 支持时序数据库存储
|
||||
- 实时/历史报警(Sql转储),支持布尔/高低限值
|
||||
|
||||
#### 演示
|
||||
|
||||
http://120.24.62.140:5000/
|
||||
|
||||
默认账户密码:superAdmin 111111
|
||||
|
||||
|
||||
#### 社区版采集插件
|
||||
> 支持分包解析/订阅
|
||||
- Modbus(Rtu/Tcp/Udp)
|
||||
@@ -25,12 +34,13 @@
|
||||
#### 社区版上传插件
|
||||
> 支持Rpc写入
|
||||
- Modbus Server
|
||||
- OPCUA Server
|
||||
- Mqtt Server
|
||||
- Mqtt Client
|
||||
- OPCUA Server (支持历史查询)
|
||||
- Mqtt Server (支持自定义json)
|
||||
- Mqtt Client (支持自定义json)
|
||||
- IotSharp Client (IotSharp网关插件,Rpc待测试)
|
||||
|
||||
> 不支持Rpc
|
||||
- RabbitMQ
|
||||
- RabbitMQ (支持自定义json)
|
||||
|
||||
|
||||
#### nuget
|
||||
@@ -101,8 +111,9 @@
|
||||
#### 支持作者
|
||||
如果对您有帮助,请点击右上角⭐Star关注,感谢支持开源!
|
||||
|
||||
若希望捐赠项目,请[点击](https://diego2098.gitee.io/thingsgateway/docs/03%E3%80%81%E6%94%AF%E6%8C%81%E9%A1%B9%E7%9B%AE%E4%B8%8EPro%E7%89%88%E8%AF%B4%E6%98%8E/%E6%94%AF%E6%8C%81%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/)查看捐赠码或使用Gitee捐赠功能
|
||||
若希望捐赠项目,请查看以下捐赠码或使用Gitee捐赠功能
|
||||
|
||||
<img src="https://gitee.com/diego2098/ThingsGateway/raw/master/Image/pay.png" height=180 />
|
||||
|
||||
#### 联系作者
|
||||
* QQ群:605534569
|
||||
|
||||
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 54 KiB |
1
handbook/build/assets/js/6dde87d0.533fbe7b.js
Normal file
1
handbook/build/assets/js/7f2059f1.595088ad.js
Normal file
1
handbook/build/assets/js/879054ab.0dacf5e1.js
Normal file
1
handbook/build/assets/js/runtime~main.58b30133.js
Normal file
@@ -0,0 +1 @@
|
||||
(()=>{"use strict";var e,t,a,r,f,d={},o={};function c(e){var t=o[e];if(void 0!==t)return t.exports;var a=o[e]={exports:{}};return d[e].call(a.exports,a,a.exports,c),a.exports}c.m=d,e=[],c.O=(t,a,r,f)=>{if(!a){var d=1/0;for(b=0;b<e.length;b++){a=e[b][0],r=e[b][1],f=e[b][2];for(var o=!0,n=0;n<a.length;n++)(!1&f||d>=f)&&Object.keys(c.O).every((e=>c.O[e](a[n])))?a.splice(n--,1):(o=!1,f<d&&(d=f));if(o){e.splice(b--,1);var i=r();void 0!==i&&(t=i)}}return t}f=f||0;for(var b=e.length;b>0&&e[b-1][2]>f;b--)e[b]=e[b-1];e[b]=[a,r,f]},c.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return c.d(t,{a:t}),t},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,c.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var f=Object.create(null);c.r(f);var d={};t=t||[null,a({}),a([]),a(a)];for(var o=2&r&&e;"object"==typeof o&&!~t.indexOf(o);o=a(o))Object.getOwnPropertyNames(o).forEach((t=>d[t]=()=>e[t]));return d.default=()=>e,c.d(f,d),f},c.d=(e,t)=>{for(var a in t)c.o(t,a)&&!c.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},c.f={},c.e=e=>Promise.all(Object.keys(c.f).reduce(((t,a)=>(c.f[a](e,t),t)),[])),c.u=e=>"assets/js/"+({22:"879054ab",53:"935f2afb",86:"0f093a7e",156:"d143b96c",175:"c361d1eb",189:"186a3eb8",195:"c4f5d8e4",217:"b8d02a9c",242:"26929101",261:"cb4f4ca9",282:"96f6c49e",320:"b86d2c6e",331:"7ec71e5c",373:"760264af",397:"13a5cec0",514:"1be78505",526:"fd321996",544:"a9d01d88",556:"39afbd6e",564:"976454a3",593:"84ef20df",623:"5ae411f8",705:"46d61d03",866:"ec4c2846",874:"6dde87d0",875:"444af13b",889:"7f2059f1",916:"f21858e6",918:"17896441",920:"1a4e3797",946:"9a8d6690",966:"4ab8a817",987:"8606c6a1",994:"53c1042e",996:"19b7f836"}[e]||e)+"."+{22:"0dacf5e1",53:"b4814792",86:"63c5ac72",156:"2384a5de",175:"ee8bab92",189:"24a97c3d",195:"43de62e4",217:"25449686",242:"143c32d8",261:"983c3141",282:"b182a2f0",320:"0fb2dcd2",331:"c0b9e422",373:"3ed61cd5",397:"6b3a2f46",443:"a35c493a",514:"79ca6d8a",523:"bb83377d",525:"ee7ff280",526:"f5d30c71",544:"0aefd47f",556:"73bcb94a",564:"a7b325a9",593:"b6365e51",623:"5d1d50cd",705:"b084f227",866:"de5833c1",874:"533fbe7b",875:"a37fbda4",889:"595088ad",916:"79872004",918:"e52e3593",920:"83cee253",946:"1f1d08eb",966:"7d0118d3",972:"a79306f2",987:"f55d8fd1",994:"8816391f",996:"7e71f890"}[e]+".js",c.miniCssF=e=>{},c.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),c.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},f="thingsgateway:",c.l=(e,t,a,d)=>{if(r[e])r[e].push(t);else{var o,n;if(void 0!==a)for(var i=document.getElementsByTagName("script"),b=0;b<i.length;b++){var u=i[b];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==f+a){o=u;break}}o||(n=!0,(o=document.createElement("script")).charset="utf-8",o.timeout=120,c.nc&&o.setAttribute("nonce",c.nc),o.setAttribute("data-webpack",f+a),o.src=e),r[e]=[t];var l=(t,a)=>{o.onerror=o.onload=null,clearTimeout(s);var f=r[e];if(delete r[e],o.parentNode&&o.parentNode.removeChild(o),f&&f.forEach((e=>e(a))),t)return t(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:o}),12e4);o.onerror=l.bind(null,o.onerror),o.onload=l.bind(null,o.onload),n&&document.head.appendChild(o)}},c.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.p="/thingsgateway/",c.gca=function(e){return e={17896441:"918",26929101:"242","879054ab":"22","935f2afb":"53","0f093a7e":"86",d143b96c:"156",c361d1eb:"175","186a3eb8":"189",c4f5d8e4:"195",b8d02a9c:"217",cb4f4ca9:"261","96f6c49e":"282",b86d2c6e:"320","7ec71e5c":"331","760264af":"373","13a5cec0":"397","1be78505":"514",fd321996:"526",a9d01d88:"544","39afbd6e":"556","976454a3":"564","84ef20df":"593","5ae411f8":"623","46d61d03":"705",ec4c2846:"866","6dde87d0":"874","444af13b":"875","7f2059f1":"889",f21858e6:"916","1a4e3797":"920","9a8d6690":"946","4ab8a817":"966","8606c6a1":"987","53c1042e":"994","19b7f836":"996"}[e]||e,c.p+c.u(e)},(()=>{var e={303:0,532:0};c.f.j=(t,a)=>{var r=c.o(e,t)?e[t]:void 0;if(0!==r)if(r)a.push(r[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var f=new Promise(((a,f)=>r=e[t]=[a,f]));a.push(r[2]=f);var d=c.p+c.u(t),o=new Error;c.l(d,(a=>{if(c.o(e,t)&&(0!==(r=e[t])&&(e[t]=void 0),r)){var f=a&&("load"===a.type?"missing":a.type),d=a&&a.target&&a.target.src;o.message="Loading chunk "+t+" failed.\n("+f+": "+d+")",o.name="ChunkLoadError",o.type=f,o.request=d,r[1](o)}}),"chunk-"+t,t)}},c.O.j=t=>0===e[t];var t=(t,a)=>{var r,f,d=a[0],o=a[1],n=a[2],i=0;if(d.some((t=>0!==e[t]))){for(r in o)c.o(o,r)&&(c.m[r]=o[r]);if(n)var b=n(c)}for(t&&t(a);i<d.length;i++)f=d[i],c.o(e,f)&&e[f]&&e[f][0](),e[f]=0;return c.O(b)},a=self.webpackChunkthingsgateway=self.webpackChunkthingsgateway||[];a.forEach(t.bind(null,0)),a.push=t.bind(null,a.push.bind(a))})()})();
|
||||
@@ -1 +0,0 @@
|
||||
(()=>{"use strict";var e,t,a,r,f,c={},d={};function o(e){var t=d[e];if(void 0!==t)return t.exports;var a=d[e]={exports:{}};return c[e].call(a.exports,a,a.exports,o),a.exports}o.m=c,e=[],o.O=(t,a,r,f)=>{if(!a){var c=1/0;for(i=0;i<e.length;i++){a=e[i][0],r=e[i][1],f=e[i][2];for(var d=!0,n=0;n<a.length;n++)(!1&f||c>=f)&&Object.keys(o.O).every((e=>o.O[e](a[n])))?a.splice(n--,1):(d=!1,f<c&&(c=f));if(d){e.splice(i--,1);var b=r();void 0!==b&&(t=b)}}return t}f=f||0;for(var i=e.length;i>0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[a,r,f]},o.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return o.d(t,{a:t}),t},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,o.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var f=Object.create(null);o.r(f);var c={};t=t||[null,a({}),a([]),a(a)];for(var d=2&r&&e;"object"==typeof d&&!~t.indexOf(d);d=a(d))Object.getOwnPropertyNames(d).forEach((t=>c[t]=()=>e[t]));return c.default=()=>e,o.d(f,c),f},o.d=(e,t)=>{for(var a in t)o.o(t,a)&&!o.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((t,a)=>(o.f[a](e,t),t)),[])),o.u=e=>"assets/js/"+({22:"879054ab",53:"935f2afb",86:"0f093a7e",156:"d143b96c",175:"c361d1eb",189:"186a3eb8",195:"c4f5d8e4",217:"b8d02a9c",242:"26929101",261:"cb4f4ca9",282:"96f6c49e",320:"b86d2c6e",331:"7ec71e5c",373:"760264af",397:"13a5cec0",514:"1be78505",526:"fd321996",544:"a9d01d88",556:"39afbd6e",564:"976454a3",593:"84ef20df",623:"5ae411f8",705:"46d61d03",866:"ec4c2846",874:"6dde87d0",875:"444af13b",889:"7f2059f1",916:"f21858e6",918:"17896441",920:"1a4e3797",946:"9a8d6690",966:"4ab8a817",987:"8606c6a1",994:"53c1042e",996:"19b7f836"}[e]||e)+"."+{22:"f2f9317e",53:"b4814792",86:"63c5ac72",156:"2384a5de",175:"ee8bab92",189:"24a97c3d",195:"f48e6acd",217:"25449686",242:"143c32d8",261:"983c3141",282:"b182a2f0",320:"b89a4fe1",331:"c0b9e422",373:"3ed61cd5",397:"6b3a2f46",443:"a35c493a",514:"79ca6d8a",523:"bb83377d",525:"ee7ff280",526:"f5d30c71",544:"0aefd47f",556:"73bcb94a",564:"a7b325a9",593:"b6365e51",623:"5d1d50cd",705:"b084f227",866:"de5833c1",874:"641bb477",875:"a37fbda4",889:"de3ea03b",916:"79872004",918:"e52e3593",920:"83cee253",946:"1f1d08eb",966:"7d0118d3",972:"a79306f2",987:"f55d8fd1",994:"8816391f",996:"7e71f890"}[e]+".js",o.miniCssF=e=>{},o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},f="thingsgateway:",o.l=(e,t,a,c)=>{if(r[e])r[e].push(t);else{var d,n;if(void 0!==a)for(var b=document.getElementsByTagName("script"),i=0;i<b.length;i++){var u=b[i];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==f+a){d=u;break}}d||(n=!0,(d=document.createElement("script")).charset="utf-8",d.timeout=120,o.nc&&d.setAttribute("nonce",o.nc),d.setAttribute("data-webpack",f+a),d.src=e),r[e]=[t];var l=(t,a)=>{d.onerror=d.onload=null,clearTimeout(s);var f=r[e];if(delete r[e],d.parentNode&&d.parentNode.removeChild(d),f&&f.forEach((e=>e(a))),t)return t(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=l.bind(null,d.onerror),d.onload=l.bind(null,d.onload),n&&document.head.appendChild(d)}},o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.p="/thingsgateway/",o.gca=function(e){return e={17896441:"918",26929101:"242","879054ab":"22","935f2afb":"53","0f093a7e":"86",d143b96c:"156",c361d1eb:"175","186a3eb8":"189",c4f5d8e4:"195",b8d02a9c:"217",cb4f4ca9:"261","96f6c49e":"282",b86d2c6e:"320","7ec71e5c":"331","760264af":"373","13a5cec0":"397","1be78505":"514",fd321996:"526",a9d01d88:"544","39afbd6e":"556","976454a3":"564","84ef20df":"593","5ae411f8":"623","46d61d03":"705",ec4c2846:"866","6dde87d0":"874","444af13b":"875","7f2059f1":"889",f21858e6:"916","1a4e3797":"920","9a8d6690":"946","4ab8a817":"966","8606c6a1":"987","53c1042e":"994","19b7f836":"996"}[e]||e,o.p+o.u(e)},(()=>{var e={303:0,532:0};o.f.j=(t,a)=>{var r=o.o(e,t)?e[t]:void 0;if(0!==r)if(r)a.push(r[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var f=new Promise(((a,f)=>r=e[t]=[a,f]));a.push(r[2]=f);var c=o.p+o.u(t),d=new Error;o.l(c,(a=>{if(o.o(e,t)&&(0!==(r=e[t])&&(e[t]=void 0),r)){var f=a&&("load"===a.type?"missing":a.type),c=a&&a.target&&a.target.src;d.message="Loading chunk "+t+" failed.\n("+f+": "+c+")",d.name="ChunkLoadError",d.type=f,d.request=c,r[1](d)}}),"chunk-"+t,t)}},o.O.j=t=>0===e[t];var t=(t,a)=>{var r,f,c=a[0],d=a[1],n=a[2],b=0;if(c.some((t=>0!==e[t]))){for(r in d)o.o(d,r)&&(o.m[r]=d[r]);if(n)var i=n(o)}for(t&&t(a);b<c.length;b++)f=c[b],o.o(e,f)&&e[f]&&e[f][0](),e[f]=0;return o.O(i)},a=self.webpackChunkthingsgateway=self.webpackChunkthingsgateway||[];a.forEach(t.bind(null,0)),a.push=t.bind(null,a.push.bind(a))})()})();
|
||||
@@ -4,8 +4,8 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="generator" content="Docusaurus v2.2.0">
|
||||
<title data-rh="true">其他配置说明 | ThingsGateway</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:url" content="https://diego2098.gitee.io/thingsgateway/docs/05、网关配置/otherconfig"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="其他配置说明 | ThingsGateway"><meta data-rh="true" name="description" content="(一)报警属性"><meta data-rh="true" property="og:description" content="(一)报警属性"><link data-rh="true" rel="icon" href="/thingsgateway/img/favicon.ico"><link data-rh="true" rel="canonical" href="https://diego2098.gitee.io/thingsgateway/docs/05、网关配置/otherconfig"><link data-rh="true" rel="alternate" href="https://diego2098.gitee.io/thingsgateway/docs/05、网关配置/otherconfig" hreflang="en"><link data-rh="true" rel="alternate" href="https://diego2098.gitee.io/thingsgateway/docs/05、网关配置/otherconfig" hreflang="x-default"><link rel="stylesheet" href="/thingsgateway/assets/css/styles.a3991719.css">
|
||||
<link rel="preload" href="/thingsgateway/assets/js/runtime~main.d5cdb1c6.js" as="script">
|
||||
<link rel="preload" href="/thingsgateway/assets/js/main.5d8abb7d.js" as="script">
|
||||
<link rel="preload" href="/thingsgateway/assets/js/runtime~main.58b30133.js" as="script">
|
||||
<link rel="preload" href="/thingsgateway/assets/js/main.968ec5b8.js" as="script">
|
||||
</head>
|
||||
<body class="navigation-with-keyboard">
|
||||
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script><div id="__docusaurus">
|
||||
@@ -13,7 +13,7 @@
|
||||
连接字符串格式:</p><ul><li>Mysql</li></ul><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">server=localhost;Database=SqlSugar4xTest;Uid=root;Pwd=haosql;</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> //有些服务器防火墙有问题需要加上 min pool size=1 避免认为是恶意请求</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ul><li>SqlServer</li></ul><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">server=.;uid=sa;pwd=haosql;database=SQLSUGAR4XTEST</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ul><li>PostgreSQL</li></ul><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">PORT=5432;DATABASE=SqlSugar4xTest;HOST=localhost;PASSWORD=haosql;USER ID=postgres</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="二历史属性">(二)历史属性<a class="hash-link" href="#二历史属性" title="Direct link to heading"></a></h3><p><img loading="lazy" src="/thingsgateway/assets/images/otherconfig2-21d951b3891ec96f750e3c7278e1e4e2.png" width="2287" height="822" class="img_ev3q"></p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="转储使能-1">转储使能<a class="hash-link" href="#转储使能-1" title="Direct link to heading"></a></h4><p>历史数据转储开启/关闭</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="数据库类型-1">数据库类型<a class="hash-link" href="#数据库类型-1" title="Direct link to heading"></a></h4><p>选择转储的时序数据库:QuestDb</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="连接字符串-1">连接字符串<a class="hash-link" href="#连接字符串-1" title="Direct link to heading"></a></h4><p>对应数据的连接字符串
|
||||
连接字符串格式:</p><ul><li>QuestDb</li></ul><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">host=localhost;port=8812;username=admin;password=quest;database=qdb;ServerCompatibilityMode=NoTypeLoading;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>QQ群里下载questdb.zip和QuestDB win启动bat文件,解压两个文件,更改QuestDB win启动bat里的对应路径,最后启动服务,重启官网就可查的历史数据
|
||||
<img loading="lazy" src="/thingsgateway/assets/images/QuestdbSet-e6a2ca678b890ff721f54decb8f81eb4.jpg" width="1617" height="894" class="img_ev3q"></p></div><footer class="theme-doc-footer docusaurus-mt-lg"><div class="theme-doc-footer-edit-meta-row row"><div class="col"><a href="https://gitee.com/diego2098/ThingsGateway/tree/master/handbook/docs/05、网关配置/5.5、其他配置.mdx" target="_blank" rel="noreferrer noopener" class="theme-edit-this-page"><svg fill="currentColor" height="20" width="20" viewBox="0 0 40 40" class="iconEdit_Z9Sw" aria-hidden="true"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div><div class="col lastUpdated_vwxv"></div></div></footer></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Docs pages navigation"><a class="pagination-nav__link pagination-nav__link--prev" href="/thingsgateway/docs/05、网关配置/plugincore"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">5.4、插件管理</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/thingsgateway/docs/06、采集驱动说明/modbus"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">6.1、Modbus驱动</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#一报警属性" class="table-of-contents__link toc-highlight">(一)报警属性</a></li><li><a href="#二历史属性" class="table-of-contents__link toc-highlight">(二)历史属性</a></li></ul></div></div></div></div></main></div></div><footer class="footer footer--dark"><div class="container container-fluid"><div class="row footer__links"><div class="col footer__col"><div class="footer__title">文档</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/thingsgateway/docs">手册</a></li></ul></div><div class="col footer__col"><div class="footer__title">社区</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://gitee.com/diego2098/ThingsGateway/issues" target="_blank" rel="noopener noreferrer" class="footer__link-item">讨论<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://gitee.com/diego2098/ThingsGateway/board" target="_blank" rel="noopener noreferrer" class="footer__link-item">看板<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div><div class="col footer__col"><div class="footer__title">更多</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://gitee.com/diego2098/ThingsGateway" target="_blank" rel="noopener noreferrer" class="footer__link-item">仓库<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div></div><div class="footer__bottom text--center"><div class="footer__copyright">Copyright © 2020-2023 Diego.</div></div></div></footer></div>
|
||||
<script src="/thingsgateway/assets/js/runtime~main.d5cdb1c6.js"></script>
|
||||
<script src="/thingsgateway/assets/js/main.5d8abb7d.js"></script>
|
||||
<script src="/thingsgateway/assets/js/runtime~main.58b30133.js"></script>
|
||||
<script src="/thingsgateway/assets/js/main.968ec5b8.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
handbook/build/img/script1.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
handbook/build/img/script2.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
@@ -28,6 +28,12 @@ import Tag from "@site/src/components/Tag.js";
|
||||
|
||||
##
|
||||
|
||||
## v1.3.0(已发布)
|
||||
|
||||
|
||||
- <Tag>新增</Tag> 添加IotSharp插件
|
||||
|
||||
|
||||
## v1.2.0(已发布)
|
||||
|
||||
|
||||
|
||||
@@ -92,5 +92,32 @@ Rpc返回Json:
|
||||
无
|
||||
|
||||
|
||||
### (三)实体脚本
|
||||
|
||||
脚本功能由cs-script实现
|
||||
<img src={require('../../static/img/script1.png').default} width="400" />
|
||||
|
||||
```
|
||||
//提供这个例子
|
||||
|
||||
//定义返回List
|
||||
List<dynamic> newModelList=new List<dynamic>();
|
||||
//input为固定传入值,在变量脚本中为变量实体类List,在设备脚本中为设备实体类List,查看上面的json说明
|
||||
foreach (var item in input)
|
||||
{
|
||||
//添加自定义值
|
||||
newModelList.Add(new
|
||||
{
|
||||
customName=item.name,//变量名称
|
||||
customValue=item.value,//变量值
|
||||
customCollectTime=item.collectTime.ToString("yyyy-MM-dd HH:mm:ss fffffff"), //采集时间,这里格式化为自定义时间格式
|
||||
});
|
||||
|
||||
}
|
||||
return newModelList;
|
||||
|
||||
```
|
||||
|
||||
<img src={require('../../static/img/script2.png').default} width="400" />
|
||||
|
||||
可以看到mqtt上传内容已经改为以上脚本返回值
|
||||
@@ -90,3 +90,6 @@ Rpc返回Json:
|
||||
|
||||
|
||||
|
||||
### (三)实体脚本
|
||||
|
||||
移至 [这里](MqttServer) 查看
|
||||
|
||||
@@ -65,4 +65,8 @@ sidebar_label: 7.4、RabbitMQClient
|
||||
```
|
||||
|
||||
### (二)变量配置
|
||||
无
|
||||
无
|
||||
|
||||
### (三)实体脚本
|
||||
|
||||
移至 [这里](MqttServer) 查看
|
||||
|
||||
@@ -74,7 +74,7 @@ function Banner() {
|
||||
<div className="ThingsGateway-get-start-btn">
|
||||
<Link className="ThingsGateway-get-start" to={useBaseUrl("docs")}>
|
||||
入门指南
|
||||
<span className="ThingsGateway-version">^1.2.0</span>
|
||||
<span className="ThingsGateway-version">^1.3.0</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
BIN
handbook/static/img/script1.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
handbook/static/img/script2.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
@@ -4,7 +4,7 @@
|
||||
<LangVersion>latestMajor</LangVersion>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
|
||||
<Version>1.2.0</Version>
|
||||
<Version>1.3.0</Version>
|
||||
<Title>ThingsGateway.Foundation.Adapter.Modbus</Title>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Authors>Diego</Authors>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<LangVersion>latestMajor</LangVersion>
|
||||
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<Version>1.2.0</Version>
|
||||
<Version>1.3.0</Version>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
|
||||
@@ -1407,7 +1407,7 @@ public class OPCUAClient : DisposableObject
|
||||
EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(m_configuration);
|
||||
|
||||
ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
|
||||
var d= await m_application.CheckApplicationInstanceCertificate(true, 0);
|
||||
var d = await m_application.CheckApplicationInstanceCertificate(true, 0);
|
||||
//var x509 = await m_configuration.SecurityConfiguration.ApplicationCertificate.Find(true);
|
||||
m_session = await Opc.Ua.Client.Session.Create(
|
||||
m_configuration,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<LangVersion>latestMajor</LangVersion>
|
||||
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<Version>1.2.0</Version>
|
||||
<Version>1.3.0</Version>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
global using System;
|
||||
|
||||
global using TouchSocket.Core;
|
||||
global using TouchSocket.Sockets;
|
||||
|
||||
@@ -5,9 +5,7 @@ using System.Threading.Tasks;
|
||||
|
||||
using ThingsGateway.Foundation.Extension;
|
||||
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Resources;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace ThingsGateway.Foundation.Adapter.Siemens
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<LangVersion>latestMajor</LangVersion>
|
||||
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<Version>1.2.0</Version>
|
||||
<Version>1.3.0</Version>
|
||||
<Title>ThingsGateway.Foundation.Adapter.Siemens</Title>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Authors>Diego</Authors>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<Platforms>AnyCPU;x86</Platforms>
|
||||
<Version>1.2.0</Version>
|
||||
<Version>1.3.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
2
src/Plugins/ThingsGateway.Modbus/GlobalUsings.cs
Normal file
@@ -0,0 +1,2 @@
|
||||
global using TouchSocket.Core;
|
||||
global using TouchSocket.Sockets;
|
||||
@@ -6,9 +6,6 @@ using ThingsGateway.Foundation;
|
||||
using ThingsGateway.Foundation.Serial;
|
||||
using ThingsGateway.Web.Foundation;
|
||||
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace ThingsGateway.Modbus
|
||||
{
|
||||
public class ModbusRtu : DriverBase, IDisposable
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
using ThingsGateway.Foundation;
|
||||
using ThingsGateway.Web.Foundation;
|
||||
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace ThingsGateway.Modbus
|
||||
{
|
||||
public class ModbusRtuOverTcp : DriverBase, IDisposable
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
using ThingsGateway.Foundation;
|
||||
using ThingsGateway.Web.Foundation;
|
||||
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace ThingsGateway.Modbus
|
||||
{
|
||||
public class ModbusRtuOverUdp : DriverBase
|
||||
|
||||
@@ -9,9 +9,6 @@ using ThingsGateway.Foundation.Adapter.Modbus;
|
||||
using ThingsGateway.Foundation.Extension;
|
||||
using ThingsGateway.Web.Foundation;
|
||||
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace ThingsGateway.Modbus
|
||||
{
|
||||
public class ModbusServer : UpLoadBase
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
using ThingsGateway.Foundation;
|
||||
using ThingsGateway.Web.Foundation;
|
||||
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace ThingsGateway.Modbus
|
||||
{
|
||||
public class ModbusTcp : DriverBase
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
using ThingsGateway.Foundation;
|
||||
using ThingsGateway.Web.Foundation;
|
||||
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
|
||||
namespace ThingsGateway.Modbus
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>1.2.0</Version>
|
||||
<Version>1.3.0</Version>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
|
||||
430
src/Plugins/ThingsGateway.Mqtt/IotSharp/IotSharpClient.cs
Normal file
@@ -0,0 +1,430 @@
|
||||
using IoTSharp.Data;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using MQTTnet;
|
||||
using MQTTnet.Client;
|
||||
|
||||
using NewLife.Serialization;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
using ThingsGateway.Foundation;
|
||||
using ThingsGateway.Foundation.Extension;
|
||||
using ThingsGateway.Web.Foundation;
|
||||
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.Mqtt
|
||||
{
|
||||
/// <summary>
|
||||
/// 参考IotSharpClient.SDK.MQTT
|
||||
/// </summary>
|
||||
public class IotSharpClient : UpLoadBase
|
||||
{
|
||||
public IotSharpClient(IServiceScopeFactory scopeFactory) : base(scopeFactory)
|
||||
{
|
||||
}
|
||||
public override OperResult IsConnected()
|
||||
{
|
||||
if (_mqttClient?.IsConnected == true)
|
||||
{
|
||||
return OperResult.CreateSuccessResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult();
|
||||
}
|
||||
}
|
||||
|
||||
[DeviceProperty("Accesstoken", "")] public string Accesstoken { get; set; } = "Accesstoken";
|
||||
[DeviceProperty("IP", "")] public string IP { get; set; } = "127.0.0.1";
|
||||
[DeviceProperty("端口", "")] public int Port { get; set; } = 1883;
|
||||
[DeviceProperty("连接超时时间", "")] public int ConnectTimeOut { get; set; } = 3000;
|
||||
[DeviceProperty("允许Rpc写入", "")] public bool DeviceRpcEnable { get; set; }
|
||||
|
||||
[DeviceProperty("循环间隔", "最小500ms")] public int CycleInterval { get; set; } = 1000;
|
||||
|
||||
|
||||
public override async Task BeforStart()
|
||||
{
|
||||
if (_mqttClient != null)
|
||||
{
|
||||
var result = await TryMqttClient();
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
_logger?.LogWarning(ToString() + $"-连接MqttServer失败:{result.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void Dispose()
|
||||
{
|
||||
_globalCollectDeviceData?.CollectVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
|
||||
|
||||
_globalCollectDeviceData?.CollectDevices?.ForEach(a =>
|
||||
{
|
||||
a.DeviceStatusCahnge -= DeviceStatusCahnge;
|
||||
});
|
||||
_mqttClient?.Dispose();
|
||||
_mqttClient = null;
|
||||
}
|
||||
|
||||
|
||||
private UploadDevice _curDevice { get; set; }
|
||||
RpcCore _rpcCore { get; set; }
|
||||
private IMqttClient _mqttClient;
|
||||
private MqttClientOptions _mqttClientOptions;
|
||||
private MqttClientSubscribeOptions _mqttSubscribeOptions;
|
||||
CollectDeviceHostService collectDeviceHostService;
|
||||
protected override void Init(UploadDevice device)
|
||||
{
|
||||
_curDevice = device;
|
||||
var mqttFactory = new MqttFactory(new PrivateLogger(_logger));
|
||||
_mqttClientOptions = mqttFactory.CreateClientOptionsBuilder()
|
||||
.WithClientId(Guid.NewGuid().ToString())
|
||||
.WithCredentials(Accesstoken)//账密
|
||||
.WithTcpServer(IP, Port)//服务器
|
||||
.WithCleanSession(true)
|
||||
.WithKeepAlivePeriod(TimeSpan.FromSeconds(120.0))
|
||||
.Build();
|
||||
_mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder()
|
||||
.WithTopicFilter(
|
||||
f =>
|
||||
{
|
||||
f.WithTopic($"devices/+/rpc/request/+/+");//RPC控制请求,需要订阅
|
||||
})
|
||||
|
||||
.Build();
|
||||
_mqttClient = mqttFactory.CreateMqttClient();
|
||||
_mqttClient.ConnectedAsync += _mqttClient_ConnectedAsync;
|
||||
_mqttClient.ApplicationMessageReceivedAsync += _mqttClient_ApplicationMessageReceivedAsync;
|
||||
using var serviceScope = _scopeFactory.CreateScope();
|
||||
_globalCollectDeviceData = serviceScope.ServiceProvider.GetService<GlobalCollectDeviceData>();
|
||||
_rpcCore = serviceScope.ServiceProvider.GetService<RpcCore>();
|
||||
collectDeviceHostService = serviceScope.GetBackgroundService<CollectDeviceHostService>();
|
||||
|
||||
_globalCollectDeviceData.CollectDevices.ForEach(a =>
|
||||
{
|
||||
a.DeviceStatusCahnge += DeviceStatusCahnge;
|
||||
});
|
||||
_globalCollectDeviceData.CollectVariables.ForEach(a =>
|
||||
{
|
||||
a.VariableValueChange += VariableValueChange;
|
||||
});
|
||||
|
||||
_ = Task.Run(
|
||||
async () =>
|
||||
{
|
||||
await Task.Delay(ConnectTimeOut * 20);
|
||||
bool lastIsSuccess = _mqttClient?.IsConnected == true;
|
||||
while (_mqttClient != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await TryMqttClient();
|
||||
|
||||
if (!result.IsSuccess && lastIsSuccess)
|
||||
{
|
||||
lastIsSuccess = false;
|
||||
_logger?.LogWarning(ToString() + $"-连接MqttServer失败:{result.Message}");
|
||||
}
|
||||
else if (result.IsSuccess && !lastIsSuccess)
|
||||
{
|
||||
lastIsSuccess = true;
|
||||
_logger?.LogInformation(ToString() + $"-连接MqttServer成功:{result.Message}");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
await Task.Delay(ConnectTimeOut * 10);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async Task _mqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg)
|
||||
{
|
||||
var subResult = await _mqttClient.SubscribeAsync(_mqttSubscribeOptions);
|
||||
|
||||
if (subResult.Items.Any(a => a.ResultCode > (MqttClientSubscribeResultCode)10))
|
||||
{
|
||||
_logger.LogWarning(subResult.Items
|
||||
.Where(a => a.ResultCode > (MqttClientSubscribeResultCode)10)
|
||||
.Select(a => a.ToString()).ToJson());
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $" {nameof(IotSharpClient)}-IP:{IP}-Port:{Port}-Accesstoken:{Accesstoken}";
|
||||
}
|
||||
|
||||
|
||||
private GlobalCollectDeviceData _globalCollectDeviceData;
|
||||
|
||||
private ConcurrentQueue<VariableData> CollectVariableRunTimes { get; set; } = new();
|
||||
private ConcurrentQueue<DeviceData> CollectDeviceRunTimes { get; set; } = new();
|
||||
|
||||
private void DeviceStatusCahnge(CollectDeviceRunTime collectDeviceRunTime)
|
||||
{
|
||||
CollectDeviceRunTimes.Enqueue(collectDeviceRunTime.Adapt<DeviceData>());
|
||||
}
|
||||
|
||||
private void VariableValueChange(CollectVariableRunTime collectVariableRunTime)
|
||||
{
|
||||
CollectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>());
|
||||
}
|
||||
private EasyLock lockobj { get; set; } = new();
|
||||
private async Task<OperResult> TryMqttClient(bool reconnect = false)
|
||||
{
|
||||
if (_mqttClient?.IsConnected == true)
|
||||
return OperResult.CreateSuccessResult();
|
||||
return await Cilent();
|
||||
|
||||
async Task<OperResult> Cilent()
|
||||
{
|
||||
if (_mqttClient?.IsConnected == true)
|
||||
return OperResult.CreateSuccessResult();
|
||||
try
|
||||
{
|
||||
lockobj.Lock();
|
||||
if (_mqttClient?.IsConnected == true)
|
||||
return OperResult.CreateSuccessResult();
|
||||
using (var timeoutToken = new CancellationTokenSource(TimeSpan.FromSeconds(ConnectTimeOut)))
|
||||
{
|
||||
if (_mqttClient?.IsConnected == true)
|
||||
return OperResult.CreateSuccessResult();
|
||||
if (_mqttClient == null)
|
||||
return new OperResult("未初始化");
|
||||
var result = await _mqttClient?.ConnectAsync(_mqttClientOptions, timeoutToken.Token);
|
||||
if (result.ResultCode == MqttClientConnectResultCode.Success)
|
||||
{
|
||||
|
||||
return OperResult.CreateSuccessResult();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return new OperResult(result.ReasonString);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OperResult(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lockobj.UnLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// rpcmethodname存疑,定为自定义方法,在ThingsGateway上写入变量的方法固定为"Write"
|
||||
/// </summary>
|
||||
private const string WriteMethod = "WRITE";
|
||||
private async Task _mqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs e)
|
||||
{
|
||||
|
||||
if (e.ApplicationMessage.Topic.StartsWith($"devices/") && e.ApplicationMessage.Topic.Contains("/rpc/request/"))
|
||||
{
|
||||
var tps = e.ApplicationMessage.Topic.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var rpcmethodname = tps[4];
|
||||
var rpcdevicename = tps[1];
|
||||
var rpcrequestid = tps[5];
|
||||
if (!string.IsNullOrEmpty(rpcmethodname) && !string.IsNullOrEmpty(rpcdevicename) && !string.IsNullOrEmpty(rpcrequestid))
|
||||
{
|
||||
var rpcResponse = new RpcResponse()
|
||||
{
|
||||
DeviceId = rpcdevicename,
|
||||
ResponseId = rpcrequestid,
|
||||
Method = rpcmethodname,
|
||||
Success = false,
|
||||
Data = "参数为空"
|
||||
};
|
||||
await SendResponse(rpcResponse);
|
||||
return;
|
||||
}
|
||||
if (!DeviceRpcEnable)
|
||||
{
|
||||
var rpcResponse = new RpcResponse()
|
||||
{
|
||||
DeviceId = rpcdevicename,
|
||||
ResponseId = rpcrequestid,
|
||||
Method = rpcmethodname,
|
||||
Success = false,
|
||||
Data = "不允许写入"
|
||||
};
|
||||
await SendResponse(rpcResponse);
|
||||
return;
|
||||
}
|
||||
//rpcmethodname定为自定义方法,在ThingsGateway上写入变量的方法固定为"Write"
|
||||
if (rpcmethodname.ToUpper() != WriteMethod)
|
||||
{
|
||||
var rpcResponse = new RpcResponse()
|
||||
{
|
||||
DeviceId = rpcdevicename,
|
||||
ResponseId = rpcrequestid,
|
||||
Method = rpcmethodname,
|
||||
Success = false,
|
||||
Data = "不支持的方法"
|
||||
};
|
||||
await SendResponse(rpcResponse);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
RpcResponse rpcResponse = new();
|
||||
var nameValue = e.ApplicationMessage.ConvertPayloadToString().ToJsonEntity<List<NameValue>>();
|
||||
Dictionary<string, OperResult> results = new();
|
||||
if (nameValue?.Count > 0)
|
||||
{
|
||||
foreach (var item in nameValue)
|
||||
{
|
||||
var result = await _rpcCore.InvokeDeviceMethod(ToString() + "-" + rpcrequestid, item);
|
||||
results.Add(item.Name, result);
|
||||
}
|
||||
rpcResponse = new()
|
||||
{
|
||||
DeviceId = rpcdevicename,
|
||||
ResponseId = rpcrequestid,
|
||||
Method = rpcmethodname,
|
||||
Success = !results.Any(a => !a.Value.IsSuccess),
|
||||
Data = results.ToJson()
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
rpcResponse = new()
|
||||
{
|
||||
DeviceId = rpcdevicename,
|
||||
ResponseId = rpcrequestid,
|
||||
Method = rpcmethodname,
|
||||
Success = false,
|
||||
Data = "消息体参数无法解析"
|
||||
};
|
||||
}
|
||||
|
||||
await SendResponse(rpcResponse);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
async Task SendResponse(RpcResponse rpcResponse)
|
||||
{
|
||||
try
|
||||
{
|
||||
var topic = $"devices/{rpcResponse.DeviceId}/rpc/response/{rpcResponse.Method}/{rpcResponse.ResponseId}";
|
||||
|
||||
var variableMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"{topic}")
|
||||
.WithPayload(rpcResponse.ToJson()).Build();
|
||||
if (_mqttClient.IsConnected)
|
||||
await _mqttClient.PublishAsync(variableMessage);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static DateTime timeSpan = new DateTime(1970, 1, 1, 0, 0, 0);
|
||||
public override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
////变化推送
|
||||
var varList = CollectVariableRunTimes.ToListWithDequeue();
|
||||
if (varList?.Count != 0)
|
||||
{
|
||||
//分解List,避免超出mqtt字节大小限制.ChunkTrivialBetter(500)
|
||||
var varData = varList.GroupBy(a=>a.deviceName).ToList();
|
||||
foreach (var item in varData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var variableMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"devices/{item.Key}/telemetry")
|
||||
.WithPayload(item.ToDictionary(o => o.name, o => o.value).ToJson()).Build();
|
||||
if (_mqttClient.IsConnected)
|
||||
await _mqttClient.PublishAsync(variableMessage, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, ToString());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger?.LogWarning(ex, ToString());
|
||||
}
|
||||
try
|
||||
{
|
||||
////变化推送
|
||||
var devList = CollectDeviceRunTimes.ToListWithDequeue();
|
||||
if (devList?.Count != 0)
|
||||
{
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var devData = devList.ChunkTrivialBetter(500);
|
||||
foreach (var item in devData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
// var variableMessage = new MqttApplicationMessageBuilder()
|
||||
//.WithTopic($"{DeviceTopic}")
|
||||
//.WithPayload(item.GetSciptListValue(BigTextScriptDeviceModel)).Build();
|
||||
// if (_mqttClient.IsConnected)
|
||||
// await _mqttClient.PublishAsync(variableMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, ToString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger?.LogWarning(ex, ToString());
|
||||
}
|
||||
|
||||
if (CycleInterval > 500 + 50)
|
||||
{
|
||||
await Task.Delay(CycleInterval - 500);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
14
src/Plugins/ThingsGateway.Mqtt/IotSharp/RpcResponse.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace IoTSharp.Data
|
||||
{
|
||||
public class RpcResponse
|
||||
{
|
||||
public string DeviceId { get; set; }
|
||||
public string Method { get; set; }
|
||||
public string ResponseId { get; set; }
|
||||
public string Data { get; set; }
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,7 +21,6 @@ namespace ThingsGateway.Mqtt
|
||||
{
|
||||
public class MqttClient : UpLoadBase
|
||||
{
|
||||
|
||||
public MqttClient(IServiceScopeFactory scopeFactory) : base(scopeFactory)
|
||||
{
|
||||
}
|
||||
@@ -47,12 +46,14 @@ namespace ThingsGateway.Mqtt
|
||||
[DeviceProperty("Rpc返回Topic", "")] public string RpcSubTopic { get; set; } = "ThingsGateway/RpcSub";
|
||||
|
||||
[DeviceProperty("数据请求RpcTopic", "这个主题接收到任何数据都会把全部的信息发送到变量/设备主题中")] public string QuestRpcTopic { get; set; } = "ThingsGateway/Quest";
|
||||
|
||||
[DeviceProperty("变量Topic", "")] public string VariableTopic { get; set; } = "ThingsGateway/Variable";
|
||||
[DeviceProperty("设备Topic", "")] public string DeviceTopic { get; set; } = "ThingsGateway/Device";
|
||||
|
||||
[DeviceProperty("循环间隔", "最小500ms")] public int CycleInterval { get; set; } = 1000;
|
||||
|
||||
[DeviceProperty("设备实体脚本", "查看文档说明,为空时不起作用")] public string BigTextScriptDeviceModel { get; set; }
|
||||
[DeviceProperty("变量实体脚本", "查看文档说明,为空时不起作用")] public string BigTextScriptVariableModel { get; set; }
|
||||
|
||||
|
||||
public override async Task BeforStart()
|
||||
{
|
||||
@@ -112,7 +113,7 @@ namespace ThingsGateway.Mqtt
|
||||
using var serviceScope = _scopeFactory.CreateScope();
|
||||
_globalCollectDeviceData = serviceScope.ServiceProvider.GetService<GlobalCollectDeviceData>();
|
||||
_rpcCore = serviceScope.ServiceProvider.GetService<RpcCore>();
|
||||
collectDeviceHostService = serviceScope.ServiceProvider.GetBackgroundService<CollectDeviceHostService>();
|
||||
collectDeviceHostService = serviceScope.GetBackgroundService<CollectDeviceHostService>();
|
||||
|
||||
_globalCollectDeviceData.CollectDevices.ForEach(a =>
|
||||
{
|
||||
@@ -238,11 +239,14 @@ namespace ThingsGateway.Mqtt
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var varData = _globalCollectDeviceData.CollectVariables.Adapt<List<VariableData>>().ChunkTrivialBetter(500);
|
||||
var devData = _globalCollectDeviceData.CollectVariables.Adapt<List<DeviceData>>().ChunkTrivialBetter(500);
|
||||
|
||||
foreach (var item in devData)
|
||||
{
|
||||
|
||||
|
||||
var devMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"{DeviceTopic}")
|
||||
.WithPayload(item.ToJson()).Build();
|
||||
.WithPayload(item.GetSciptListValue(BigTextScriptDeviceModel)).Build();
|
||||
await _mqttClient.PublishAsync(devMessage);
|
||||
}
|
||||
|
||||
@@ -250,7 +254,7 @@ namespace ThingsGateway.Mqtt
|
||||
{
|
||||
var varMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"{VariableTopic}")
|
||||
.WithPayload(item.ToJson()).Build();
|
||||
.WithPayload(item.GetSciptListValue(BigTextScriptVariableModel)).Build();
|
||||
await _mqttClient.PublishAsync(varMessage);
|
||||
}
|
||||
}
|
||||
@@ -311,11 +315,19 @@ namespace ThingsGateway.Mqtt
|
||||
{
|
||||
try
|
||||
{
|
||||
var variableMessage = new MqttApplicationMessageBuilder()
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var variableMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"{VariableTopic}")
|
||||
.WithPayload(item.ToJson()).Build();
|
||||
if (_mqttClient.IsConnected)
|
||||
await _mqttClient.PublishAsync(variableMessage);
|
||||
.WithPayload(item.GetSciptListValue(BigTextScriptVariableModel)).Build();
|
||||
if (_mqttClient.IsConnected)
|
||||
await _mqttClient.PublishAsync(variableMessage, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -341,11 +353,18 @@ namespace ThingsGateway.Mqtt
|
||||
{
|
||||
try
|
||||
{
|
||||
var variableMessage = new MqttApplicationMessageBuilder()
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var variableMessage = new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"{DeviceTopic}")
|
||||
.WithPayload(item.ToJson()).Build();
|
||||
if (_mqttClient.IsConnected)
|
||||
await _mqttClient.PublishAsync(variableMessage);
|
||||
.WithPayload(item.GetSciptListValue(BigTextScriptDeviceModel)).Build();
|
||||
if (_mqttClient.IsConnected)
|
||||
await _mqttClient.PublishAsync(variableMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -42,6 +42,10 @@ namespace ThingsGateway.Mqtt
|
||||
[DeviceProperty("设备Topic", "")] public string DeviceTopic { get; set; } = "ThingsGateway/Device";
|
||||
[DeviceProperty("循环间隔", "最小500ms")] public int CycleInterval { get; set; } = 1000;
|
||||
|
||||
[DeviceProperty("设备实体脚本", "查看文档说明,为空时不起作用")] public string BigTextScriptDeviceModel { get; set; }
|
||||
[DeviceProperty("变量实体脚本", "查看文档说明,为空时不起作用")] public string BigTextScriptVariableModel { get; set; }
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $" {nameof(MqttServer)} IP:{IP} Port:{Port}";
|
||||
@@ -80,13 +84,13 @@ namespace ThingsGateway.Mqtt
|
||||
{
|
||||
Messages.Add(new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"{VariableTopic}")
|
||||
.WithPayload(item.ToJson()).Build());
|
||||
.WithPayload(item.GetSciptListValue(BigTextScriptVariableModel)).Build());
|
||||
}
|
||||
foreach (var item in devData)
|
||||
{
|
||||
Messages.Add(new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"{DeviceTopic}")
|
||||
.WithPayload(item.ToJson()).Build());
|
||||
.WithPayload(item.GetSciptListValue(BigTextScriptDeviceModel)).Build());
|
||||
}
|
||||
arg.LoadedRetainedMessages = Messages;
|
||||
return CompletedTask.Instance;
|
||||
@@ -215,11 +219,18 @@ namespace ThingsGateway.Mqtt
|
||||
{
|
||||
try
|
||||
{
|
||||
var message = new MqttApplicationMessageBuilder()
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var message = new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"{VariableTopic}")
|
||||
.WithPayload(item.ToJson()).Build();
|
||||
await _mqttServer.InjectApplicationMessage(
|
||||
new InjectedMqttApplicationMessage(message));
|
||||
.WithPayload(item.GetSciptListValue(BigTextScriptVariableModel)).Build();
|
||||
await _mqttServer.InjectApplicationMessage(
|
||||
new InjectedMqttApplicationMessage(message));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -247,11 +258,18 @@ namespace ThingsGateway.Mqtt
|
||||
{
|
||||
try
|
||||
{
|
||||
var message = new MqttApplicationMessageBuilder()
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var message = new MqttApplicationMessageBuilder()
|
||||
.WithTopic($"{DeviceTopic}")
|
||||
.WithPayload(item.ToJson()).Build();
|
||||
await _mqttServer.InjectApplicationMessage(
|
||||
new InjectedMqttApplicationMessage(message));
|
||||
.WithPayload(item.GetSciptListValue(BigTextScriptDeviceModel)).Build();
|
||||
await _mqttServer.InjectApplicationMessage(
|
||||
new InjectedMqttApplicationMessage(message));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<Version>1.2.0</Version>
|
||||
<Version>1.3.0</Version>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<Version>1.2.0</Version>
|
||||
<Version>1.3.0</Version>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
||||
@@ -62,7 +62,7 @@ public partial class OPCUAServer : UpLoadBase
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
public override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -74,7 +74,14 @@ public partial class OPCUAServer : UpLoadBase
|
||||
{
|
||||
try
|
||||
{
|
||||
m_server.NodeManager.UpVariable(item);
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
m_server.NodeManager.UpVariable(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -121,7 +128,7 @@ public partial class OPCUAServer : UpLoadBase
|
||||
|
||||
private void VariableValueChange(CollectVariableRunTime collectVariableRunTime)
|
||||
{
|
||||
CollectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>());
|
||||
CollectVariableRunTimes.Enqueue(collectVariableRunTime.Adapt<VariableData>());
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +221,7 @@ public partial class OPCUAServer : UpLoadBase
|
||||
TrustedPeerCertificates = new CertificateTrustList()
|
||||
{
|
||||
StoreType = CertificateStoreType.Directory,
|
||||
StorePath = "%CommonApplicationData%\\ThingsGateway\\pki\\issuer",
|
||||
StorePath = "%CommonApplicationData%\\ThingsGateway\\pki\\issuer",
|
||||
},
|
||||
|
||||
TrustedIssuerCertificates = new CertificateTrustList()
|
||||
|
||||
@@ -7,6 +7,8 @@ using Opc.Ua.Server;
|
||||
|
||||
using ThingsGateway.Web.Foundation;
|
||||
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.OPCUA;
|
||||
|
||||
|
||||
@@ -25,12 +27,18 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
|
||||
private Dictionary<NodeId, OPCUATag> _idTags = new Dictionary<NodeId, OPCUATag>();
|
||||
private RpcCore _rpcCore;
|
||||
private IServiceScope _serviceScope;
|
||||
private TypeAdapterConfig _config;
|
||||
/// <inheritdoc cref="ThingsGatewayNodeManager"/>
|
||||
public ThingsGatewayNodeManager(IServiceScope serviceScope, IServerInternal server, ApplicationConfiguration configuration) : base(server, configuration, ReferenceServer)
|
||||
{
|
||||
_serviceScope = serviceScope;
|
||||
_rpcCore = serviceScope.ServiceProvider.GetService<RpcCore>();
|
||||
_globalCollectDeviceData = serviceScope.ServiceProvider.GetService<GlobalCollectDeviceData>();
|
||||
_config = new TypeAdapterConfig();
|
||||
_config.ForType<ValueHis, DataValue>()
|
||||
.Map(dest => dest.WrappedValue, (src) => new Variant(src.Value))
|
||||
.Map(dest => dest.SourceTimestamp, (src) => src.CollectTime)
|
||||
.Map(dest => dest.StatusCode, (src) => src.Quality == 192 ? StatusCodes.Good : StatusCodes.Bad);
|
||||
}
|
||||
|
||||
|
||||
@@ -84,12 +92,20 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 读取历史数据
|
||||
/// </summary>
|
||||
public override void HistoryRead(OperationContext context, HistoryReadDetails details, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, IList<HistoryReadValueId> nodesToRead, IList<HistoryReadResult> results, IList<ServiceResult> errors)
|
||||
public override void HistoryRead(OperationContext context,
|
||||
HistoryReadDetails details,
|
||||
TimestampsToReturn timestampsToReturn,
|
||||
bool releaseContinuationPoints,
|
||||
IList<HistoryReadValueId> nodesToRead,
|
||||
IList<HistoryReadResult> results,
|
||||
IList<ServiceResult> errors)
|
||||
{
|
||||
ReadProcessedDetails readDetail = details as ReadProcessedDetails;
|
||||
base.HistoryRead(context, details, timestampsToReturn, releaseContinuationPoints, nodesToRead, results, errors);
|
||||
var readDetail = details as ReadRawModifiedDetails;
|
||||
//必须带有时间范围
|
||||
if (readDetail == null || readDetail.StartTime == DateTime.MinValue || readDetail.EndTime == DateTime.MinValue)
|
||||
{
|
||||
@@ -125,10 +141,17 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
|
||||
|
||||
if (data.Count > 0)
|
||||
{
|
||||
|
||||
var hisDataValue = data.Adapt<List<DataValue>>(_config);
|
||||
HistoryData hisData = new HistoryData();
|
||||
hisData.DataValues.AddRange(hisDataValue);
|
||||
errors[i] = StatusCodes.Good;
|
||||
//切记Processed设为true,否则客户端会报错
|
||||
historyRead.Processed = true;
|
||||
results[i] = new HistoryReadResult()
|
||||
{
|
||||
StatusCode = StatusCodes.Good,
|
||||
HistoryData = new ExtensionObject(data)
|
||||
HistoryData = new ExtensionObject(hisData)
|
||||
};
|
||||
}
|
||||
else
|
||||
@@ -147,7 +170,6 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
|
||||
};
|
||||
}
|
||||
}
|
||||
base.HistoryRead(context, details, timestampsToReturn, releaseContinuationPoints, nodesToRead, results, errors);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override NodeId New(ISystemContext context, NodeState node)
|
||||
@@ -261,15 +283,13 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
|
||||
variable.WriteMask = AttributeWriteMask.DisplayName | AttributeWriteMask.Description;
|
||||
variable.UserWriteMask = AttributeWriteMask.DisplayName | AttributeWriteMask.Description;
|
||||
variable.ValueRank = ValueRanks.Scalar;
|
||||
|
||||
|
||||
variable.Id = variableRunTime.Id;
|
||||
variable.DataType = DataNodeType(variableRunTime);
|
||||
var level = ProtectTypeTrans(variableRunTime.ProtectTypeEnum);
|
||||
var level = ProtectTypeTrans(variableRunTime);
|
||||
variable.AccessLevel = level;
|
||||
variable.UserAccessLevel = level;
|
||||
variable.Historizing = variableRunTime.HisEnable;
|
||||
|
||||
variable.Historizing = false;
|
||||
variable.StatusCode = StatusCodes.Good;
|
||||
variable.Timestamp = DateTime.Now;
|
||||
variable.Value = Opc.Ua.TypeInfo.GetDefaultValue(variable.DataType, ValueRanks.Scalar, Server.TypeTree);
|
||||
@@ -278,7 +298,7 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
|
||||
{
|
||||
parent.AddChild(variable);
|
||||
}
|
||||
_idTags.Add(variable.NodeId, variable);
|
||||
_idTags.AddOrUpdate(variable.NodeId, variable);
|
||||
return variable;
|
||||
}
|
||||
|
||||
@@ -365,15 +385,26 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
|
||||
|
||||
}
|
||||
|
||||
private byte ProtectTypeTrans(ProtectTypeEnum protectTypeEnum)
|
||||
private byte ProtectTypeTrans(CollectVariableRunTime variableRunTime)
|
||||
{
|
||||
switch (protectTypeEnum)
|
||||
byte result = 0;
|
||||
switch (variableRunTime.ProtectTypeEnum)
|
||||
{
|
||||
case ProtectTypeEnum.ReadOnly: return AccessLevels.CurrentRead;
|
||||
case ProtectTypeEnum.ReadOnly:
|
||||
result = (byte)(result | AccessLevels.CurrentRead);
|
||||
break;
|
||||
case ProtectTypeEnum.ReadWrite:
|
||||
return AccessLevels.CurrentReadOrWrite;
|
||||
result = (byte)(result | AccessLevels.CurrentReadOrWrite);
|
||||
break;
|
||||
default:
|
||||
return AccessLevels.CurrentRead;
|
||||
result = (byte)(result | AccessLevels.CurrentRead);
|
||||
break;
|
||||
}
|
||||
if (variableRunTime.HisEnable)
|
||||
{
|
||||
result = (byte)(result | AccessLevels.HistoryRead);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ public partial class ThingsGatewayServer : StandardServer
|
||||
_logger = logger;
|
||||
_serviceScope = serviceScope;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override UserTokenPolicyCollection GetUserTokenPolicies(ApplicationConfiguration configuration, EndpointDescription description)
|
||||
{
|
||||
@@ -234,7 +233,7 @@ public partial class ThingsGatewayServer : StandardServer
|
||||
"Security token is not a valid username token. An empty password is not accepted.");
|
||||
}
|
||||
var _openApiUserService = _serviceScope.ServiceProvider.GetService<IOpenApiUserService>();
|
||||
var userInfo = _openApiUserService.GetUserByAccount(userName).GetAwaiter().GetResult();//获取用户信息
|
||||
var userInfo = _openApiUserService.GetUserByAccount(userName).GetAwaiter().GetResult();//获取用户信息
|
||||
if (userInfo == null)
|
||||
{
|
||||
// construct translation object with default text.
|
||||
@@ -260,7 +259,7 @@ public partial class ThingsGatewayServer : StandardServer
|
||||
{
|
||||
return new UserIdentity(userNameToken);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
private void VerifyUserTokenCertificate(X509Certificate2 certificate)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<Version>1.2.0</Version>
|
||||
<Version>1.3.0</Version>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using NewLife.Serialization;
|
||||
|
||||
using RabbitMQ.Client;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
@@ -14,8 +12,6 @@ using ThingsGateway.Foundation;
|
||||
using ThingsGateway.Foundation.Extension;
|
||||
using ThingsGateway.Web.Foundation;
|
||||
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.RabbitMQ
|
||||
{
|
||||
public class RabbitMQClient : UpLoadBase
|
||||
@@ -49,6 +45,8 @@ namespace ThingsGateway.RabbitMQ
|
||||
[DeviceProperty("是否发布List", "")] public bool IsList { get; set; } = false;
|
||||
[DeviceProperty("是否声明队列", "")] public bool IsQueueDeclare { get; set; } = false;
|
||||
[DeviceProperty("循环间隔", "最小500ms")] public int CycleInterval { get; set; } = 1000;
|
||||
[DeviceProperty("设备实体脚本", "查看文档说明,为空时不起作用")] public string BigTextScriptDeviceModel { get; set; }
|
||||
[DeviceProperty("变量实体脚本", "查看文档说明,为空时不起作用")] public string BigTextScriptVariableModel { get; set; }
|
||||
|
||||
public string ExchangeName { get; set; } = "";
|
||||
|
||||
@@ -136,6 +134,7 @@ namespace ThingsGateway.RabbitMQ
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
// 创建连接
|
||||
if (_connection == null)
|
||||
_connection = _connectionFactory.CreateConnection();
|
||||
@@ -148,6 +147,8 @@ namespace ThingsGateway.RabbitMQ
|
||||
_model?.QueueDeclare(VariableQueueName, true, false, false);
|
||||
_model?.QueueDeclare(DeviceQueueName, true, false, false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -168,11 +169,18 @@ namespace ThingsGateway.RabbitMQ
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = Encoding.UTF8.GetBytes(variables.ToJson());
|
||||
// 设置消息持久化
|
||||
IBasicProperties properties = _model?.CreateBasicProperties();
|
||||
properties.Persistent = true;
|
||||
_model?.BasicPublish(ExchangeName, VariableQueueName, properties, data);
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var data = Encoding.UTF8.GetBytes(variables.GetSciptListValue(BigTextScriptVariableModel));
|
||||
// 设置消息持久化
|
||||
IBasicProperties properties = _model?.CreateBasicProperties();
|
||||
properties.Persistent = true;
|
||||
_model?.BasicPublish(ExchangeName, VariableQueueName, properties, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -187,11 +195,19 @@ namespace ThingsGateway.RabbitMQ
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = Encoding.UTF8.GetBytes(variable.ToJson());
|
||||
// 设置消息持久化
|
||||
IBasicProperties properties = _model?.CreateBasicProperties();
|
||||
properties.Persistent = true;
|
||||
_model?.BasicPublish(ExchangeName, VariableQueueName, properties, data);
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var data = Encoding.UTF8.GetBytes(variable.GetSciptListValue(BigTextScriptVariableModel));
|
||||
// 设置消息持久化
|
||||
IBasicProperties properties = _model?.CreateBasicProperties();
|
||||
properties.Persistent = true;
|
||||
_model?.BasicPublish(ExchangeName, VariableQueueName, properties, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -220,7 +236,7 @@ namespace ThingsGateway.RabbitMQ
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = Encoding.UTF8.GetBytes(devices.ToJson());
|
||||
var data = Encoding.UTF8.GetBytes(devices.GetSciptListValue(BigTextScriptDeviceModel));
|
||||
// 设置消息持久化
|
||||
IBasicProperties properties = _model?.CreateBasicProperties();
|
||||
properties.Persistent = true;
|
||||
@@ -239,7 +255,7 @@ namespace ThingsGateway.RabbitMQ
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = Encoding.UTF8.GetBytes(devices.ToJson());
|
||||
var data = Encoding.UTF8.GetBytes(devices.GetSciptListValue(BigTextScriptDeviceModel));
|
||||
// 设置消息持久化
|
||||
IBasicProperties properties = _model?.CreateBasicProperties();
|
||||
properties.Persistent = true;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>1.2.0</Version>
|
||||
<Version>1.3.0</Version>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
global using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
global using System.Net;
|
||||
|
||||
global using ThingsGateway.Foundation.Adapter.Siemens;
|
||||
global using ThingsGateway.Web.Foundation;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>1.2.0</Version>
|
||||
<Version>1.3.0</Version>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
namespace System.ComponentModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 操作事件说明
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class OperDescAttribute : Attribute
|
||||
{
|
||||
@@ -13,9 +16,17 @@
|
||||
Description = description;
|
||||
Catcategory = catcategory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分类
|
||||
/// </summary>
|
||||
public string Catcategory { get; }
|
||||
/// <summary>
|
||||
/// 说明
|
||||
/// </summary>
|
||||
public string Description { get; }
|
||||
/// <summary>
|
||||
/// 记录参数
|
||||
/// </summary>
|
||||
public bool IsRecordPar { get; set; } = true;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
using Furion.Reflection;
|
||||
using Furion.Reflection.Extensions;
|
||||
|
||||
using System.Text;
|
||||
|
||||
namespace ThingsGateway.Application
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace ThingsGateway.Web.Entry.Controllers
|
||||
namespace ThingsGateway.Application
|
||||
{
|
||||
/// <summary>
|
||||
/// B端登录控制器
|
||||
@@ -13,7 +13,10 @@ namespace ThingsGateway.Web.Entry.Controllers
|
||||
public class AuthController : IDynamicApiController
|
||||
{
|
||||
private readonly IAuthService _authService;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="AuthController"/>
|
||||
/// </summary>
|
||||
/// <param name="authService"></param>
|
||||
public AuthController(IAuthService authService)
|
||||
{
|
||||
_authService = authService;
|
||||
@@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
using ThingsGateway.Application.Services.Auth;
|
||||
|
||||
namespace ThingsGateway.Web.Entry.Controllers
|
||||
namespace ThingsGateway.Application
|
||||
{
|
||||
/// <summary>
|
||||
/// OpenApi登录控制器
|
||||
@@ -17,7 +17,10 @@ namespace ThingsGateway.Web.Entry.Controllers
|
||||
public class OpenApiAuthController : IDynamicApiController
|
||||
{
|
||||
private readonly OpenApiAuthService _authService;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="OpenApiAuthController"/>
|
||||
/// </summary>
|
||||
/// <param name="authService"></param>
|
||||
public OpenApiAuthController(OpenApiAuthService authService)
|
||||
{
|
||||
_authService = authService;
|
||||
@@ -1,11 +1,10 @@
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.DynamicApiController;
|
||||
using Furion.DynamicApiController;
|
||||
using Furion.SpecificationDocument;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace ThingsGateway.Web.Entry.Controllers
|
||||
namespace ThingsGateway.Application
|
||||
{
|
||||
/// <summary>
|
||||
/// 系统登录授权服务
|
||||
@@ -16,7 +15,11 @@ namespace ThingsGateway.Web.Entry.Controllers
|
||||
{
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly ConfigService _configService;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="SwaggerController"/>
|
||||
/// </summary>
|
||||
/// <param name="sysConfigService"></param>
|
||||
/// <param name="cache"></param>
|
||||
public SwaggerController(ConfigService sysConfigService,
|
||||
IMemoryCache cache)
|
||||
{
|
||||
@@ -7,7 +7,11 @@
|
||||
{
|
||||
private readonly SqlSugarScope _db;
|
||||
private readonly SysCacheService _sysCacheService;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="AuthEventSubscriber"/>
|
||||
/// </summary>
|
||||
/// <param name="sysCacheService"></param>
|
||||
/// <param name="services"></param>
|
||||
public AuthEventSubscriber(SysCacheService sysCacheService, IServiceProvider services)
|
||||
{
|
||||
_db = DbContext.Db;
|
||||
@@ -15,7 +19,7 @@
|
||||
this._services = services;
|
||||
}
|
||||
|
||||
public IServiceProvider _services { get; }
|
||||
private IServiceProvider _services { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 登录事件
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
public class UserEventSubscriber : IEventSubscriber, ISingleton
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="UserEventSubscriber"/>
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
public UserEventSubscriber(IServiceProvider services)
|
||||
{
|
||||
this._services = services;
|
||||
|
||||
@@ -9,7 +9,9 @@ namespace ThingsGateway.Application
|
||||
{
|
||||
private readonly ICache _cache;
|
||||
private string _symbol = "TBCache_TBCache";
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="ApplicationCacheService"/>
|
||||
/// </summary>
|
||||
public ApplicationCacheService()
|
||||
{
|
||||
_cache = new MemoryCache();
|
||||
@@ -18,8 +20,6 @@ namespace ThingsGateway.Application
|
||||
/// <summary>
|
||||
/// 检查缓存是否存在
|
||||
/// </summary>
|
||||
/// <param name="key">键</param>
|
||||
/// <returns></returns>
|
||||
public bool ExistKey(string prefixKey, string key)
|
||||
{
|
||||
var str = prefixKey + _symbol + key;
|
||||
@@ -29,9 +29,6 @@ namespace ThingsGateway.Application
|
||||
/// <summary>
|
||||
/// 获取缓存
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public T Get<T>(string prefixKey, string key)
|
||||
{
|
||||
var str = prefixKey + _symbol + key;
|
||||
@@ -41,8 +38,6 @@ namespace ThingsGateway.Application
|
||||
/// <summary>
|
||||
/// 根据键名前缀获取缓存
|
||||
/// </summary>
|
||||
/// <param name="prefixKey">键名前缀</param>
|
||||
/// <returns></returns>
|
||||
public IDictionary<string, T> GetByPrefixKey<T>(string prefixKey)
|
||||
{
|
||||
var delKeys = _cache.Keys.Where(u => u.Split(_symbol).FirstOrDefault() == prefixKey).ToArray();
|
||||
@@ -53,8 +48,6 @@ namespace ThingsGateway.Application
|
||||
/// <summary>
|
||||
/// 根据键名前缀获取全部中间key
|
||||
/// </summary>
|
||||
/// <param name="prefixKey">键名前缀</param>
|
||||
/// <returns></returns>
|
||||
public List<long> GetKeyByPrefixKey(string prefixKey)
|
||||
{
|
||||
var delKeys = _cache.Keys.SelectMany(u =>
|
||||
@@ -74,9 +67,6 @@ namespace ThingsGateway.Application
|
||||
/// <summary>
|
||||
/// 获取缓存
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public T GetOrAdd<T>(string prefixKey, string key, Func<string, T> func, int expire = -1)
|
||||
{
|
||||
var str = prefixKey + _symbol + key;
|
||||
@@ -86,8 +76,6 @@ namespace ThingsGateway.Application
|
||||
/// <summary>
|
||||
/// 删除缓存
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public void Remove(string prefixKey, string key)
|
||||
{
|
||||
var str = prefixKey + _symbol + key;
|
||||
@@ -109,9 +97,6 @@ namespace ThingsGateway.Application
|
||||
/// <summary>
|
||||
/// 增加缓存
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public void Set(string prefixKey, string key, object value)
|
||||
{
|
||||
var str = prefixKey + _symbol + key;
|
||||
@@ -121,10 +106,6 @@ namespace ThingsGateway.Application
|
||||
/// <summary>
|
||||
/// 增加缓存并设置过期时间
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="expire"></param>
|
||||
/// <returns></returns>
|
||||
public void Set(string prefixKey, string key, object value, TimeSpan expire)
|
||||
{
|
||||
var str = prefixKey + _symbol + key;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
using System.Globalization;
|
||||
|
||||
namespace ThingsGateway.Application
|
||||
{
|
||||
/// <summary>
|
||||
/// 扩展方法
|
||||
/// </summary>
|
||||
public static class ApplicationExtension
|
||||
{
|
||||
private static ApplicationCacheService ApplicationCacheService;
|
||||
@@ -14,6 +16,10 @@ namespace ThingsGateway.Application
|
||||
ApplicationCacheService = App.GetService<ApplicationCacheService>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取全部Api授权树
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<OpenApiPermissionTreeSelector> OpenApiPermissionTreeSelector()
|
||||
{
|
||||
var cacheKey = $"{nameof(OpenApiPermissionTreeSelector)}-{CultureInfo.CurrentUICulture.Name}";
|
||||
|
||||
@@ -5,6 +5,7 @@ global using Furion.FriendlyException;
|
||||
|
||||
global using Mapster;
|
||||
|
||||
global using Microsoft.AspNetCore.Authorization;
|
||||
global using Microsoft.AspNetCore.Http;
|
||||
global using Microsoft.AspNetCore.SignalR;
|
||||
global using Microsoft.CodeAnalysis;
|
||||
@@ -15,13 +16,15 @@ global using NewLife.Serialization;
|
||||
|
||||
global using SqlSugar;
|
||||
|
||||
global using System;
|
||||
global using System.ComponentModel;
|
||||
global using System.ComponentModel.DataAnnotations;
|
||||
global using System.Reflection;
|
||||
global using System.Text;
|
||||
global using System.Threading.Tasks;
|
||||
|
||||
global using ThingsGateway.Core;
|
||||
global using ThingsGateway.Core.Extension;
|
||||
|
||||
global using ThingsGateway.Core.Utils;
|
||||
|
||||
global using Yitter.IdGenerator;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using Furion.Schedule;
|
||||
|
||||
using System.Threading;
|
||||
|
||||
namespace ThingsGateway.Web.Core;
|
||||
|
||||
/// <summary>
|
||||
@@ -12,12 +10,15 @@ namespace ThingsGateway.Web.Core;
|
||||
public class LogJob : IJob
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="LogJob"/>
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
public LogJob(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
|
||||
{
|
||||
var db = DbContext.Db.CopyNew();
|
||||
@@ -7,7 +7,7 @@
|
||||
{
|
||||
private readonly SqlSugarScope _db;
|
||||
private readonly SysCacheService _sysCacheService;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public OpenApiAuthEventSubscriber(SysCacheService sysCacheService, IServiceProvider services)
|
||||
{
|
||||
_db = DbContext.Db;
|
||||
@@ -15,7 +15,7 @@
|
||||
this._services = services;
|
||||
}
|
||||
|
||||
public IServiceProvider _services { get; }
|
||||
private IServiceProvider _services { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 登录事件
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
/// </summary>
|
||||
public class LoginOpenApiOutPut : BaseLoginOutPut
|
||||
{
|
||||
/// <summary>
|
||||
/// TOKEN
|
||||
/// </summary>
|
||||
public string Token { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,20 @@
|
||||
namespace ThingsGateway.Application.Services.Auth
|
||||
{
|
||||
/// <summary>
|
||||
/// 登录服务
|
||||
/// </summary>
|
||||
public interface IOpenApiAuthService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 登录
|
||||
/// </summary>
|
||||
/// <param name="input">登录参数</param>
|
||||
/// <returns>Token信息</returns>
|
||||
Task<LoginOpenApiOutPut> LoginOpenApi(LoginOpenApiInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 登出
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task LoginOut();
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authentication;
|
||||
|
||||
namespace ThingsGateway.Application.Services.Auth
|
||||
{
|
||||
/// <inheritdoc cref="IOpenApiAuthService"/>
|
||||
public class OpenApiAuthService : IOpenApiAuthService, ITransient
|
||||
{
|
||||
private readonly IConfigService _configService;
|
||||
@@ -11,6 +12,7 @@ namespace ThingsGateway.Application.Services.Auth
|
||||
private readonly IOpenApiUserService _openApiUserService;
|
||||
private readonly SysCacheService _sysCacheService;
|
||||
|
||||
/// <inheritdoc cref="IOpenApiAuthService"/>
|
||||
public OpenApiAuthService(
|
||||
IEventPublisher eventPublisher,
|
||||
IOpenApiUserService openApiUserService,
|
||||
|
||||