27 Commits

Author SHA1 Message Date
779e21909c Added All Device handler 2020-11-18 18:34:48 +01:00
f84ea8f0c5 Extended Devices with buttons and status 2020-11-18 14:04:57 +01:00
181985859e Added componentDidMount heatmap initializer 2020-11-18 12:35:33 +01:00
39a38fe8eb Added context to heatmap, and devices 2020-11-18 12:04:32 +01:00
490f0f3265 Added context 2020-11-18 09:56:30 +01:00
41bf14a4e5 Merge branch 'master' into feature/Contexts 2020-11-18 09:19:05 +01:00
3f267cb009 Added background color, Added Accordion onChange handler 2020-11-17 22:20:50 +01:00
0e3eb8720f Added Devices Accordions 2020-11-17 21:51:53 +01:00
3f2467f6c6 Added Device Context (not working) 2020-11-17 18:58:28 +01:00
2a83856622 Removed exact from NavLink to fix highlighting 2020-11-13 19:11:25 +01:00
d726273431 Added position offset, changed color 2020-11-12 22:11:42 +01:00
412647617b Added markers with device openers 2020-11-12 21:20:04 +01:00
53ff60ae5a Added devices id route parameter 2020-11-12 18:57:27 +01:00
f273823c93 Migrated to .NET 5, added records 2020-11-12 18:13:23 +01:00
c92808ac7d Added single update 2020-11-11 20:56:21 +01:00
f13133829a Extended DeviceHub with update notifiers 2020-11-11 20:35:26 +01:00
4c1258dc33 Added Trello docs 2020-11-11 17:13:13 +01:00
a52f6acd71 Added google maps heatmap 2020-11-11 16:55:50 +01:00
4281c2d524 Added isAdmin 2020-11-09 18:30:43 +01:00
639e6edac6 Moved interface 2020-11-09 18:13:02 +01:00
3632e56dc4 Added Mqtt and SignalR 2020-11-09 18:12:07 +01:00
b87d90e5a4 Preparing mqtt 2020-11-08 23:29:50 +01:00
f1c1ad69cc Renamed some files 2020-11-08 19:11:12 +01:00
f102b89a21 Added MQTT tester, added input service 2020-11-08 18:51:19 +01:00
e1a596dae9 Updated csproj 2020-11-07 14:20:58 +01:00
7f1a85d430 Added Device services for back and frontend 2020-11-07 14:19:29 +01:00
05a8d7f090 Added logout button functionality 2020-11-04 12:34:37 +01:00
75 changed files with 7261 additions and 285 deletions

View File

@ -1,12 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<SpaRoot>ClientApp\</SpaRoot>
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
<AssemblyName>Birdmap.API</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
@ -20,9 +21,9 @@
<ItemGroup>
<PackageReference Include="AutoMapper" Version="10.1.1" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.9" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="3.1.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.9">
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="5.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@ -30,7 +31,13 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MQTTnet" Version="3.0.13" />
<PackageReference Include="MQTTnet.AspNetCore" Version="3.0.13" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NLog" Version="4.7.5" />
<PackageReference Include="NLog.Web" Version="4.9.3" />
<PackageReference Include="NLog.Web.AspNetCore" Version="4.9.3" />
<PackageReference Include="NSwag.AspNetCore" Version="13.9.0" />
</ItemGroup>
<ItemGroup>
@ -42,21 +49,19 @@
<ItemGroup>
<None Remove="ClientApp\src\common\components\BirdmapTitle.tsx" />
<None Remove="ClientApp\src\common\ErrorDispatcher.ts" />
<None Remove="ClientApp\src\common\ServiceBase.ts" />
<None Remove="ClientApp\src\components\auth\Auth.tsx" />
<None Remove="ClientApp\src\components\auth\AuthClient.ts" />
<None Remove="ClientApp\src\components\auth\AuthService.ts" />
<None Remove="ClientApp\src\components\devices\DeviceService.ts" />
</ItemGroup>
<ItemGroup>
<TypeScriptCompile Include="ClientApp\src\components\auth\Auth.tsx" />
<TypeScriptCompile Include="ClientApp\src\common\components\BirdmapTitle.tsx" />
</ItemGroup>
<ItemGroup>
<Folder Include="ClientApp\src\common\components\" />
<Folder Include="ClientApp\src\components\dashboard\" />
<Folder Include="ClientApp\src\components\devices\" />
<Folder Include="ClientApp\src\components\heatmap\" />
</ItemGroup>
<ItemGroup>

View File

@ -1199,6 +1199,11 @@
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
"integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
},
"@googlemaps/js-api-loader": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.8.0.tgz",
"integrity": "sha512-aFxlJVFOC00KELhlaqU6tpnxj9szVdG7OSHxQzc9uhp4Ky8/zvYNnzZg2S+pPvhe+WkJPugQL8fowP5nYTBXUg=="
},
"@hapi/address": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz",
@ -1424,6 +1429,11 @@
"@types/yargs": "^13.0.0"
}
},
"@mapbox/point-geometry": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz",
"integrity": "sha1-ioP5M1x4YO/6Lu7KJUMyqgru2PI="
},
"@material-ui/core": {
"version": "4.11.0",
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.0.tgz",
@ -1559,6 +1569,33 @@
"react-is": "^16.8.0"
}
},
"@microsoft/signalr": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-5.0.0.tgz",
"integrity": "sha512-AsbU1ZB4Q9JsZ77W13VGT8gi/cVrFn3XbvVfULSwrC9DVCXF2JpkBDh0cCmRaYs9M3kqKohiVM1WPqNeAGil/g==",
"requires": {
"abort-controller": "^3.0.0",
"eventsource": "^1.0.7",
"fetch-cookie": "^0.7.3",
"node-fetch": "^2.6.0",
"ws": "^6.0.0"
},
"dependencies": {
"node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
},
"ws": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
"requires": {
"async-limiter": "~1.0.0"
}
}
}
},
"@mrmlnc/readdir-enhanced": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
@ -1733,6 +1770,11 @@
"@types/node": "*"
}
},
"@types/googlemaps": {
"version": "3.40.3",
"resolved": "https://registry.npmjs.org/@types/googlemaps/-/googlemaps-3.40.3.tgz",
"integrity": "sha512-ivlG5S0LlnQgpgPnQCUNAs7kjBtO367ZwDmuK+ggsQfW+w4N0RyWbxWZ6vPwegDe50Du3Xbb5+QVwJuB/U1XpA=="
},
"@types/history": {
"version": "4.7.3",
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.3.tgz",
@ -2165,6 +2207,14 @@
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
"integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q=="
},
"abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"requires": {
"event-target-shim": "^5.0.0"
}
},
"accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
@ -3401,6 +3451,11 @@
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
},
"can-use-dom": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/can-use-dom/-/can-use-dom-0.1.0.tgz",
"integrity": "sha1-IsxKNKCrxDlQ9CxkEQJKP2NmtFo="
},
"caniuse-api": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
@ -3445,6 +3500,11 @@
"supports-color": "^5.3.0"
}
},
"change-emitter": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/change-emitter/-/change-emitter-0.1.6.tgz",
"integrity": "sha1-6LL+PX8at9aaMhma/5HqaTFAlRU="
},
"chardet": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
@ -4852,6 +4912,24 @@
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"encoding": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
"requires": {
"iconv-lite": "^0.6.2"
},
"dependencies": {
"iconv-lite": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
"integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
}
}
},
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
@ -4967,6 +5045,11 @@
"next-tick": "~1.0.0"
}
},
"es6-denodeify": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/es6-denodeify/-/es6-denodeify-0.1.5.tgz",
"integrity": "sha1-MdTV/pxVA+ElRgQ5MQ4WoqPznB8="
},
"es6-iterator": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
@ -5493,6 +5576,11 @@
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
},
"eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
@ -5852,6 +5940,44 @@
"bser": "2.1.1"
}
},
"fbjs": {
"version": "0.8.17",
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz",
"integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=",
"requires": {
"core-js": "^1.0.0",
"isomorphic-fetch": "^2.1.1",
"loose-envify": "^1.0.0",
"object-assign": "^4.1.0",
"promise": "^7.1.1",
"setimmediate": "^1.0.5",
"ua-parser-js": "^0.7.18"
},
"dependencies": {
"core-js": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "~2.0.3"
}
}
}
},
"fetch-cookie": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.7.3.tgz",
"integrity": "sha512-rZPkLnI8x5V+zYAiz8QonAHsTb4BY+iFowFBI1RFn0zrO343AVp9X7/yUj/9wL6Ef/8fLls8b/vGtzUvmyAUGA==",
"requires": {
"es6-denodeify": "^0.1.1",
"tough-cookie": "^2.3.3"
}
},
"figgy-pudding": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
@ -6321,6 +6447,35 @@
}
}
},
"google-map-react": {
"version": "2.1.9",
"resolved": "https://registry.npmjs.org/google-map-react/-/google-map-react-2.1.9.tgz",
"integrity": "sha512-//Pa0o6sdspU2H0ehVztSDQSnYYeV6TY4Z6ftty34yiCJYLliOzeq17dA9uFkyUFdL+XwbTU6e9mfs+bjBMIzw==",
"requires": {
"@googlemaps/js-api-loader": "^1.7.0",
"@mapbox/point-geometry": "^0.1.0",
"eventemitter3": "^4.0.4",
"prop-types": "^15.7.2"
}
},
"google-maps": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/google-maps/-/google-maps-4.3.3.tgz",
"integrity": "sha512-MQbEgBNQbGyV7mfS2tlFgW4EoGKLia24BvAl4a+kgsYWt4283kyPpaay/yKIsScQLr7nSUONaLNfOdMsCuJDEw==",
"requires": {
"@types/googlemaps": "^3.39.1"
}
},
"google-maps-infobox": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/google-maps-infobox/-/google-maps-infobox-2.0.0.tgz",
"integrity": "sha512-hTuWmWZZSOxf5D/z7l3/hTF1grgRvLG53BEKMdjiKOG+FcK/kH7vqseUeyIU9Zj2ZIqKTOaro0nknxpAuRq4Vw=="
},
"google-maps-react": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/google-maps-react/-/google-maps-react-2.0.6.tgz",
"integrity": "sha512-M8Eo9WndfQEfxcmm6yRq03qdJgw1x6rQmJ9DN+a+xPQ3K7yNDGkVDbinrf4/8vcox7nELbeopbm4bpefKewWfQ=="
},
"graceful-fs": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
@ -7189,6 +7344,15 @@
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
},
"isomorphic-fetch": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
"integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
"requires": {
"node-fetch": "^1.0.1",
"whatwg-fetch": ">=0.10.0"
}
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@ -8303,6 +8467,16 @@
"object-visit": "^1.0.0"
}
},
"marker-clusterer-plus": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/marker-clusterer-plus/-/marker-clusterer-plus-2.1.4.tgz",
"integrity": "sha1-+O/3TVmdqzt9Dj/tUmTqDnBPXWc="
},
"markerwithlabel": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/markerwithlabel/-/markerwithlabel-2.0.2.tgz",
"integrity": "sha512-C/cbm1A0h/u54gwHk5ZJNdUU3V3+1BbCpRPMsMyFA7vF4yL+aB4rWpxACz29TpQ+cTg6/iQroExh0PMSRGtQFg=="
},
"md5.js": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@ -8716,6 +8890,15 @@
"tslib": "^1.10.0"
}
},
"node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
"requires": {
"encoding": "^0.1.11",
"is-stream": "^1.0.1"
}
},
"node-forge": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
@ -10791,6 +10974,50 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.7.tgz",
"integrity": "sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA=="
},
"react-google-maps": {
"version": "9.4.5",
"resolved": "https://registry.npmjs.org/react-google-maps/-/react-google-maps-9.4.5.tgz",
"integrity": "sha512-8z5nX9DxIcBCXuEiurmRT1VXVwnzx0C6+3Es6lxB2/OyY2SLax2/LcDu6Aldxnl3HegefTL7NJzGeaKAJ61pOA==",
"requires": {
"babel-runtime": "^6.11.6",
"can-use-dom": "^0.1.0",
"google-maps-infobox": "^2.0.0",
"invariant": "^2.2.1",
"lodash": "^4.16.2",
"marker-clusterer-plus": "^2.1.4",
"markerwithlabel": "^2.0.1",
"prop-types": "^15.5.8",
"recompose": "^0.26.0",
"scriptjs": "^2.5.8",
"warning": "^3.0.0"
},
"dependencies": {
"hoist-non-react-statics": {
"version": "2.5.5",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
"integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw=="
},
"recompose": {
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/recompose/-/recompose-0.26.0.tgz",
"integrity": "sha512-KwOu6ztO0mN5vy3+zDcc45lgnaUoaQse/a5yLVqtzTK13czSWnFGmXbQVmnoMgDkI5POd1EwIKSbjU1V7xdZog==",
"requires": {
"change-emitter": "^0.1.2",
"fbjs": "^0.8.1",
"hoist-non-react-statics": "^2.3.1",
"symbol-observable": "^1.0.4"
}
},
"warning": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
"integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
"requires": {
"loose-envify": "^1.0.0"
}
}
}
},
"react-is": {
"version": "16.12.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz",
@ -11171,6 +11398,26 @@
"util.promisify": "^1.0.0"
}
},
"recompose": {
"version": "0.30.0",
"resolved": "https://registry.npmjs.org/recompose/-/recompose-0.30.0.tgz",
"integrity": "sha512-ZTrzzUDa9AqUIhRk4KmVFihH0rapdCSMFXjhHbNrjAWxBuUD/guYlyysMnuHjlZC/KRiOKRtB4jf96yYSkKE8w==",
"requires": {
"@babel/runtime": "^7.0.0",
"change-emitter": "^0.1.2",
"fbjs": "^0.8.1",
"hoist-non-react-statics": "^2.3.1",
"react-lifecycles-compat": "^3.0.2",
"symbol-observable": "^1.0.4"
},
"dependencies": {
"hoist-non-react-statics": {
"version": "2.5.5",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
"integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw=="
}
}
},
"recursive-readdir": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz",
@ -11730,6 +11977,11 @@
}
}
},
"scriptjs": {
"version": "2.5.9",
"resolved": "https://registry.npmjs.org/scriptjs/-/scriptjs-2.5.9.tgz",
"integrity": "sha512-qGVDoreyYiP1pkQnbnFAUIS5AjenNwwQBdl7zeos9etl+hYKWahjRTfzAZZYBv5xNHx7vNKCmaLDQZ6Fr2AEXg=="
},
"seamless-immutable": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/seamless-immutable/-/seamless-immutable-7.1.4.tgz",
@ -13244,6 +13496,11 @@
"integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==",
"dev": true
},
"ua-parser-js": {
"version": "0.7.22",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.22.tgz",
"integrity": "sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q=="
},
"unicode-canonical-property-names-ecmascript": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",

View File

@ -6,19 +6,25 @@
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.56",
"@microsoft/signalr": "^5.0.0",
"bootstrap": "^4.3.1",
"connected-react-router": "6.5.2",
"google-map-react": "^2.1.9",
"google-maps": "^4.3.3",
"google-maps-react": "^2.0.6",
"history": "4.10.1",
"jquery": "^3.5.1",
"merge": "1.2.1",
"popper.js": "^1.16.0",
"react": "16.11.0",
"react": "^16.11.0",
"react-dom": "16.11.0",
"react-google-maps": "^9.4.5",
"react-redux": "7.1.1",
"react-router": "5.1.2",
"react-router-dom": "5.1.2",
"react-scripts": "^3.4.4",
"reactstrap": "8.1.1",
"recompose": "^0.30.0",
"redux": "4.0.4",
"redux-thunk": "2.3.0",
"svgo": "1.3.0"

View File

@ -22,11 +22,11 @@
-->
<title>Birdmap</title>
</head>
<body>
<body style="height: 100vh;">
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<div id="root" style="height: 100vh;"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.

View File

@ -1,26 +1,32 @@
import { Box, Container, IconButton, Menu, MenuItem } from '@material-ui/core';
import { Box, Container, IconButton, Menu, MenuItem, MenuList, Paper, Grow, Popper } from '@material-ui/core';
import AccountCircle from '@material-ui/icons/AccountCircle';
import AppBar from '@material-ui/core/AppBar';
import blue from '@material-ui/core/colors/blue';
import orange from '@material-ui/core/colors/orange';
import { positions } from '@material-ui/system';
import { createMuiTheme, createStyles, makeStyles, Theme } from '@material-ui/core/styles';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import { ThemeProvider } from '@material-ui/styles';
import React, { useState } from 'react';
import { BrowserRouter, NavLink, Redirect, Route, Switch } from 'react-router-dom';
import BirdmapTitle from './common/components/BirdmapTitle';
import React, { useState, } from 'react';
import { BrowserRouter, NavLink, Redirect, Route, Switch, Link } from 'react-router-dom';
import BirdmapTitle from './components/appBar/BirdmapTitle';
import Auth from './components/auth/Auth';
import AuthService from './components/auth/AuthService';
import { ClickAwayListener } from '@material-ui/core';
import MapContainer from './components/heatmap/Heatmap';
import Devices from './components/devices/Devices';
import { blueGrey, blue, orange, grey } from '@material-ui/core/colors';
import DevicesContextProvider from './contexts/DevicesContextProvider'
const theme = createMuiTheme({
palette: {
primary: {
main: blue[900],
main: blueGrey[900],
dark: grey[400],
},
secondary: {
main: orange[200],
dark: blueGrey[50],
}
},
});
@ -28,9 +34,11 @@ const theme = createMuiTheme({
function App() {
const [authenticated, setAuthenticated] = useState(AuthService.isAuthenticated());
const [isAdmin, setIsAdmin] = useState(AuthService.isAdmin());
const onAuthenticated = () => {
setAuthenticated(AuthService.isAuthenticated());
setIsAdmin(AuthService.isAdmin());
};
const AuthComponent = () => {
@ -40,15 +48,19 @@ function App() {
}
const DashboardComponent = () => {
return <Typography>Dashboard</Typography>;
return <Link to="/devices/5">This is a link</Link>;
};
const DevicesComponent = () => {
return <Typography>Devices</Typography>;
return <Devices isAdmin={isAdmin}/>;
};
const HeatmapComponent = () => {
return <Typography>Heatmap</Typography>;
return (
<Paper elevation={0}>
<MapContainer />
</Paper>
);
};
return (
@ -56,9 +68,11 @@ function App() {
<BrowserRouter>
<Switch>
<PublicRoute path="/login" component={AuthComponent} />
<DevicesContextProvider>
<PrivateRoute path="/" exact authenticated={authenticated} component={DashboardComponent} />
<PrivateRoute path="/devices" exact authenticated={authenticated} component={DevicesComponent} />
<PrivateRoute path="/devices/:id?" exact authenticated={authenticated} component={DevicesComponent} />
<PrivateRoute path="/heatmap" exact authenticated={authenticated} component={HeatmapComponent} />
</DevicesContextProvider>
</Switch>
</BrowserRouter>
</ThemeProvider>
@ -70,7 +84,7 @@ export default App;
const PublicRoute = ({ component: Component, ...rest }: { [x: string]: any, component: any}) => {
return (
<Route {...rest} render={matchProps => (
<DefaultLayout component={Component} authenticated={false} {...matchProps} />
<DefaultLayout component={Component} authenticated={false} isAdmin={false} {...matchProps} />
)} />
);
}
@ -87,53 +101,83 @@ const PrivateRoute = ({ component: Component, authenticated: Authenticated, ...r
const DefaultLayout = ({ component: Component, authenticated: Authenticated, ...rest }: { [x: string]: any, component: any, authenticated: any }) => {
const classes = useDefaultLayoutStyles();
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef<HTMLButtonElement>(null);
const handleMenu = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
const handleToggle = () => {
setOpen((prevOpen) => !prevOpen);
};
const handleClose = () => {
setAnchorEl(null);
const handleClose = (event: React.MouseEvent<EventTarget>) => {
if (anchorRef.current && anchorRef.current.contains(event.target as HTMLElement)) {
return;
}
setOpen(false);
};
const handleLogout = (event: React.MouseEvent<EventTarget>) => {
if (anchorRef.current && anchorRef.current.contains(event.target as HTMLElement)) {
return;
}
AuthService.logout();
setOpen(false);
};
function handleListKeyDown(event: React.KeyboardEvent) {
if (event.key === 'Tab') {
event.preventDefault();
setOpen(false);
}
}
const prevOpen = React.useRef(open);
React.useEffect(() => {
if (prevOpen.current === true && open === false) {
anchorRef.current!.focus();
}
prevOpen.current = open;
}, [open]);
const renderNavLinks = () => {
return Authenticated
? <Container className={classes.nav_menu}>
<NavLink exact to="/" className={classes.nav_menu_item} activeClassName={classes.nav_menu_item_active}>Dashboard</NavLink>
<NavLink exact to="/devices" className={classes.nav_menu_item} activeClassName={classes.nav_menu_item_active}>Devices</NavLink>
<NavLink to="/devices" className={classes.nav_menu_item} activeClassName={classes.nav_menu_item_active}>Devices</NavLink>
<NavLink exact to="/heatmap" className={classes.nav_menu_item} activeClassName={classes.nav_menu_item_active}>Heatmap</NavLink>
<IconButton className={classes.nav_menu_icon}
ref={anchorRef}
aria-haspopup="true"
aria-controls="menu-appbar"
aria-controls={open ? 'menu-list-grow' : undefined}
aria-label="account of current user"
onClick={handleMenu}>
onClick={handleToggle}>
<AccountCircle/>
</IconButton>
<Menu
id="menu-appbar"
anchorEl={anchorEl}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={open}
onClose={handleClose}>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</Menu>
<Popper open={open} anchorEl={anchorRef.current} role={undefined} transition disablePortal>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{ transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom' }}>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id="menu-list-grow" onKeyDown={handleListKeyDown}>
<MenuItem onClick={handleLogout} component={Link} {...{ to: '/login' }}>Logout</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</Container>
: null;
};
return (
<React.Fragment>
<AppBar position="static">
<AppBar position="static" className={classes.bar_root}>
<Toolbar>
<BirdmapTitle />
<Typography component={'span'} className={classes.typo}>
@ -141,7 +185,7 @@ const DefaultLayout = ({ component: Component, authenticated: Authenticated, ...
</Typography>
</Toolbar>
</AppBar>
<Box style={{ margin: '32px' }}>
<Box zIndex="modal" className={classes.box_root}>
<Component {...rest} />
</Box>
</React.Fragment>
@ -150,6 +194,13 @@ const DefaultLayout = ({ component: Component, authenticated: Authenticated, ...
const useDefaultLayoutStyles = makeStyles((theme: Theme) =>
createStyles({
bar_root: {
height: '7%',
},
box_root: {
backgroundColor: theme.palette.primary.dark,
height: '93%',
},
typo: {
marginLeft: 'auto',
color: 'white',

View File

@ -0,0 +1,5 @@
export default {
probability_method_name: 'NotifyDeviceAsync',
update_method_name: 'NotifyDeviceUpdatedAsync',
update_all_method_name: 'NotifyAllUpdatedAsync',
};

View File

@ -0,0 +1,616 @@
"use strict";
/* tslint:disable */
/* eslint-disable */
//----------------------
// <auto-generated>
// Generated using the NSwag toolchain v13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------
// ReSharper disable InconsistentNaming
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ApiException = exports.SensorStatus = exports.Coordinates = exports.DeviceStatus = exports.Sensor = exports.Device = void 0;
var DeviceService = /** @class */ (function () {
function DeviceService(baseUrl, http) {
this.jsonParseReviver = undefined;
this.http = http ? http : window;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "api/devices";
}
/**
* Get all device info
* @return Array of devices
*/
DeviceService.prototype.getall = function () {
var _this = this;
var url_ = this.baseUrl;
var options_ = {
method: "GET",
headers: {
"Accept": "application/json",
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then(function (_response) {
return _this.processGetall(_response);
});
};
DeviceService.prototype.processGetall = function (response) {
var _this = this;
var status = response.status;
var _headers = {};
if (response.headers && response.headers.forEach) {
response.headers.forEach(function (v, k) { return _headers[k] = v; });
}
;
if (status === 200) {
return response.text().then(function (_responseText) {
var result200 = null;
var resultData200 = _responseText === "" ? null : JSON.parse(_responseText, _this.jsonParseReviver);
if (Array.isArray(resultData200)) {
result200 = [];
for (var _i = 0, resultData200_1 = resultData200; _i < resultData200_1.length; _i++) {
var item = resultData200_1[_i];
result200.push(Device.fromJS(item));
}
}
return result200;
});
}
else if (status === 404) {
return response.text().then(function (_responseText) {
return throwException("No device found", status, _responseText, _headers);
});
}
else if (status !== 200 && status !== 204) {
return response.text().then(function (_responseText) {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve(null);
};
/**
* Shut down all devices
* @return Message sent
*/
DeviceService.prototype.offlineall = function () {
var _this = this;
var url_ = this.baseUrl + "/offline";
url_ = url_.replace(/[?&]$/, "");
var options_ = {
method: "POST",
headers: {
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then(function (_response) {
return _this.processOfflineall(_response);
});
};
DeviceService.prototype.processOfflineall = function (response) {
var status = response.status;
var _headers = {};
if (response.headers && response.headers.forEach) {
response.headers.forEach(function (v, k) { return _headers[k] = v; });
}
;
if (status === 200) {
return response.text().then(function (_responseText) {
return;
});
}
else if (status === 500) {
return response.text().then(function (_responseText) {
return throwException("Message sending unsuccessful", status, _responseText, _headers);
});
}
else if (status !== 200 && status !== 204) {
return response.text().then(function (_responseText) {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve(null);
};
/**
* Bring all devices online
* @return Message sent
*/
DeviceService.prototype.onlineall = function () {
var _this = this;
var url_ = this.baseUrl + "/online";
url_ = url_.replace(/[?&]$/, "");
var options_ = {
method: "POST",
headers: {
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then(function (_response) {
return _this.processOnlineall(_response);
});
};
DeviceService.prototype.processOnlineall = function (response) {
var status = response.status;
var _headers = {};
if (response.headers && response.headers.forEach) {
response.headers.forEach(function (v, k) { return _headers[k] = v; });
}
;
if (status === 200) {
return response.text().then(function (_responseText) {
return;
});
}
else if (status === 500) {
return response.text().then(function (_responseText) {
return throwException("Message sending unsuccessful", status, _responseText, _headers);
});
}
else if (status !== 200 && status !== 204) {
return response.text().then(function (_responseText) {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve(null);
};
/**
* Get all device info
* @param deviceID ID of device to query
* @return Information about a particular device
*/
DeviceService.prototype.getdevice = function (deviceID) {
var _this = this;
var url_ = this.baseUrl + "/{deviceID}";
if (deviceID === undefined || deviceID === null)
throw new Error("The parameter 'deviceID' must be defined.");
url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID));
url_ = url_.replace(/[?&]$/, "");
var options_ = {
method: "GET",
headers: {
"Accept": "application/json",
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then(function (_response) {
return _this.processGetdevice(_response);
});
};
DeviceService.prototype.processGetdevice = function (response) {
var _this = this;
var status = response.status;
var _headers = {};
if (response.headers && response.headers.forEach) {
response.headers.forEach(function (v, k) { return _headers[k] = v; });
}
;
if (status === 200) {
return response.text().then(function (_responseText) {
var result200 = null;
var resultData200 = _responseText === "" ? null : JSON.parse(_responseText, _this.jsonParseReviver);
result200 = Device.fromJS(resultData200);
return result200;
});
}
else if (status === 404) {
return response.text().then(function (_responseText) {
return throwException("Device not found", status, _responseText, _headers);
});
}
else if (status !== 200 && status !== 204) {
return response.text().then(function (_responseText) {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve(null);
};
/**
* Shut down device
* @param deviceID ID of device to shut down
* @return Message sent
*/
DeviceService.prototype.offlinedevice = function (deviceID) {
var _this = this;
var url_ = this.baseUrl + "/{deviceID}/offline";
if (deviceID === undefined || deviceID === null)
throw new Error("The parameter 'deviceID' must be defined.");
url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID));
url_ = url_.replace(/[?&]$/, "");
var options_ = {
method: "POST",
headers: {
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then(function (_response) {
return _this.processOfflinedevice(_response);
});
};
DeviceService.prototype.processOfflinedevice = function (response) {
var status = response.status;
var _headers = {};
if (response.headers && response.headers.forEach) {
response.headers.forEach(function (v, k) { return _headers[k] = v; });
}
;
if (status === 200) {
return response.text().then(function (_responseText) {
return;
});
}
else if (status === 500) {
return response.text().then(function (_responseText) {
return throwException("Message sending unsuccessful", status, _responseText, _headers);
});
}
else if (status !== 200 && status !== 204) {
return response.text().then(function (_responseText) {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve(null);
};
/**
* Bring device online
* @param deviceID ID of device to bring online
* @return Message sent
*/
DeviceService.prototype.onlinedevice = function (deviceID) {
var _this = this;
var url_ = this.baseUrl + "/{deviceID}/online";
if (deviceID === undefined || deviceID === null)
throw new Error("The parameter 'deviceID' must be defined.");
url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID));
url_ = url_.replace(/[?&]$/, "");
var options_ = {
method: "POST",
headers: {
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then(function (_response) {
return _this.processOnlinedevice(_response);
});
};
DeviceService.prototype.processOnlinedevice = function (response) {
var status = response.status;
var _headers = {};
if (response.headers && response.headers.forEach) {
response.headers.forEach(function (v, k) { return _headers[k] = v; });
}
;
if (status === 200) {
return response.text().then(function (_responseText) {
return;
});
}
else if (status === 500) {
return response.text().then(function (_responseText) {
return throwException("Message sending unsuccessful", status, _responseText, _headers);
});
}
else if (status !== 200 && status !== 204) {
return response.text().then(function (_responseText) {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve(null);
};
/**
* Get info about a particular device's sensor
* @param deviceID ID of device to query
* @param sensorID ID of sensor to query
* @return Information about a sensor
*/
DeviceService.prototype.getsensor = function (deviceID, sensorID) {
var _this = this;
var url_ = this.baseUrl + "/{deviceID}/{sensorID}";
if (deviceID === undefined || deviceID === null)
throw new Error("The parameter 'deviceID' must be defined.");
url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID));
if (sensorID === undefined || sensorID === null)
throw new Error("The parameter 'sensorID' must be defined.");
url_ = url_.replace("{sensorID}", encodeURIComponent("" + sensorID));
url_ = url_.replace(/[?&]$/, "");
var options_ = {
method: "GET",
headers: {
"Accept": "application/json",
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then(function (_response) {
return _this.processGetsensor(_response);
});
};
DeviceService.prototype.processGetsensor = function (response) {
var _this = this;
var status = response.status;
var _headers = {};
if (response.headers && response.headers.forEach) {
response.headers.forEach(function (v, k) { return _headers[k] = v; });
}
;
if (status === 200) {
return response.text().then(function (_responseText) {
var result200 = null;
var resultData200 = _responseText === "" ? null : JSON.parse(_responseText, _this.jsonParseReviver);
result200 = Sensor.fromJS(resultData200);
return result200;
});
}
else if (status === 404) {
return response.text().then(function (_responseText) {
return throwException("Device or sensor not found", status, _responseText, _headers);
});
}
else if (status !== 200 && status !== 204) {
return response.text().then(function (_responseText) {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve(null);
};
/**
* Shut down sensor
* @param deviceID ID of device to query
* @param sensorID ID of sensor to query
* @return Message sent
*/
DeviceService.prototype.offlinesensor = function (deviceID, sensorID) {
var _this = this;
var url_ = this.baseUrl + "/{deviceID}/{sensorID}/offline";
if (deviceID === undefined || deviceID === null)
throw new Error("The parameter 'deviceID' must be defined.");
url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID));
if (sensorID === undefined || sensorID === null)
throw new Error("The parameter 'sensorID' must be defined.");
url_ = url_.replace("{sensorID}", encodeURIComponent("" + sensorID));
url_ = url_.replace(/[?&]$/, "");
var options_ = {
method: "POST",
headers: {
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then(function (_response) {
return _this.processOfflinesensor(_response);
});
};
DeviceService.prototype.processOfflinesensor = function (response) {
var status = response.status;
var _headers = {};
if (response.headers && response.headers.forEach) {
response.headers.forEach(function (v, k) { return _headers[k] = v; });
}
;
if (status === 200) {
return response.text().then(function (_responseText) {
return;
});
}
else if (status === 500) {
return response.text().then(function (_responseText) {
return throwException("Message sending unsuccessful", status, _responseText, _headers);
});
}
else if (status !== 200 && status !== 204) {
return response.text().then(function (_responseText) {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve(null);
};
/**
* Bring sensor online
* @param deviceID ID of device to query
* @param sensorID ID of sensor to query
* @return Message sent
*/
DeviceService.prototype.onlinesensor = function (deviceID, sensorID) {
var _this = this;
var url_ = this.baseUrl + "/{deviceID}/{sensorID}/online";
if (deviceID === undefined || deviceID === null)
throw new Error("The parameter 'deviceID' must be defined.");
url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID));
if (sensorID === undefined || sensorID === null)
throw new Error("The parameter 'sensorID' must be defined.");
url_ = url_.replace("{sensorID}", encodeURIComponent("" + sensorID));
url_ = url_.replace(/[?&]$/, "");
var options_ = {
method: "POST",
headers: {
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then(function (_response) {
return _this.processOnlinesensor(_response);
});
};
DeviceService.prototype.processOnlinesensor = function (response) {
var status = response.status;
var _headers = {};
if (response.headers && response.headers.forEach) {
response.headers.forEach(function (v, k) { return _headers[k] = v; });
}
;
if (status === 200) {
return response.text().then(function (_responseText) {
return;
});
}
else if (status === 500) {
return response.text().then(function (_responseText) {
return throwException("Message sending unsuccessful", status, _responseText, _headers);
});
}
else if (status !== 200 && status !== 204) {
return response.text().then(function (_responseText) {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve(null);
};
return DeviceService;
}());
exports.default = DeviceService;
var Device = /** @class */ (function () {
function Device(data) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
this[property] = data[property];
}
}
if (!data) {
this.coordinates = new Coordinates();
this.sensors = [];
}
}
Device.prototype.init = function (_data) {
if (_data) {
this.id = _data["id"];
this.status = _data["status"];
this.url = _data["url"];
this.coordinates = _data["coordinates"] ? Coordinates.fromJS(_data["coordinates"]) : new Coordinates();
if (Array.isArray(_data["sensors"])) {
this.sensors = [];
for (var _i = 0, _a = _data["sensors"]; _i < _a.length; _i++) {
var item = _a[_i];
this.sensors.push(Sensor.fromJS(item));
}
}
}
};
Device.fromJS = function (data) {
data = typeof data === 'object' ? data : {};
var result = new Device();
result.init(data);
return result;
};
Device.prototype.toJSON = function (data) {
data = typeof data === 'object' ? data : {};
data["id"] = this.id;
data["status"] = this.status;
data["url"] = this.url;
data["coordinates"] = this.coordinates ? this.coordinates.toJSON() : undefined;
if (Array.isArray(this.sensors)) {
data["sensors"] = [];
for (var _i = 0, _a = this.sensors; _i < _a.length; _i++) {
var item = _a[_i];
data["sensors"].push(item.toJSON());
}
}
return data;
};
return Device;
}());
exports.Device = Device;
var Sensor = /** @class */ (function () {
function Sensor(data) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
this[property] = data[property];
}
}
}
Sensor.prototype.init = function (_data) {
if (_data) {
this.id = _data["id"];
this.status = _data["status"];
}
};
Sensor.fromJS = function (data) {
data = typeof data === 'object' ? data : {};
var result = new Sensor();
result.init(data);
return result;
};
Sensor.prototype.toJSON = function (data) {
data = typeof data === 'object' ? data : {};
data["id"] = this.id;
data["status"] = this.status;
return data;
};
return Sensor;
}());
exports.Sensor = Sensor;
var DeviceStatus;
(function (DeviceStatus) {
DeviceStatus["Online"] = "online";
DeviceStatus["Error"] = "error";
DeviceStatus["Offline"] = "offline";
})(DeviceStatus = exports.DeviceStatus || (exports.DeviceStatus = {}));
var Coordinates = /** @class */ (function () {
function Coordinates(data) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
this[property] = data[property];
}
}
}
Coordinates.prototype.init = function (_data) {
if (_data) {
this.latitude = _data["latitude"];
this.longitude = _data["longitude"];
}
};
Coordinates.fromJS = function (data) {
data = typeof data === 'object' ? data : {};
var result = new Coordinates();
result.init(data);
return result;
};
Coordinates.prototype.toJSON = function (data) {
data = typeof data === 'object' ? data : {};
data["latitude"] = this.latitude;
data["longitude"] = this.longitude;
return data;
};
return Coordinates;
}());
exports.Coordinates = Coordinates;
var SensorStatus;
(function (SensorStatus) {
SensorStatus["Online"] = "online";
SensorStatus["Unknown"] = "unknown";
SensorStatus["Offline"] = "offline";
})(SensorStatus = exports.SensorStatus || (exports.SensorStatus = {}));
var ApiException = /** @class */ (function (_super) {
__extends(ApiException, _super);
function ApiException(message, status, response, headers, result) {
var _this = _super.call(this) || this;
_this.isApiException = true;
_this.message = message;
_this.status = status;
_this.response = response;
_this.headers = headers;
_this.result = result;
return _this;
}
ApiException.isApiException = function (obj) {
return obj.isApiException === true;
};
return ApiException;
}(Error));
exports.ApiException = ApiException;
function throwException(message, status, response, headers, result) {
if (result !== null && result !== undefined)
throw result;
else
throw new ApiException(message, status, response, headers, null);
}
//# sourceMappingURL=DeviceService.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,608 @@
/* tslint:disable */
/* eslint-disable */
//----------------------
// <auto-generated>
// Generated using the NSwag toolchain v13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------
// ReSharper disable InconsistentNaming
export default class DeviceService {
private http: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> };
private baseUrl: string;
protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined;
constructor(baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
this.http = http ? http : <any>window;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "api/devices";
}
/**
* Get all device info
* @return Array of devices
*/
getall(): Promise<Device[]> {
let url_ = this.baseUrl;
let options_ = <RequestInit>{
method: "GET",
headers: {
"Accept": "application/json",
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processGetall(_response);
});
}
protected processGetall(response: Response): Promise<Device[]> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
return response.text().then((_responseText) => {
let result200: any = null;
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
if (Array.isArray(resultData200)) {
result200 = [] as any;
for (let item of resultData200)
result200!.push(Device.fromJS(item));
}
return result200;
});
} else if (status === 404) {
return response.text().then((_responseText) => {
return throwException("No device found", status, _responseText, _headers);
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<Device[]>(<any>null);
}
/**
* Shut down all devices
* @return Message sent
*/
offlineall(): Promise<void> {
let url_ = this.baseUrl + "/offline";
url_ = url_.replace(/[?&]$/, "");
let options_ = <RequestInit>{
method: "POST",
headers: {
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processOfflineall(_response);
});
}
protected processOfflineall(response: Response): Promise<void> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
return response.text().then((_responseText) => {
return;
});
} else if (status === 500) {
return response.text().then((_responseText) => {
return throwException("Message sending unsuccessful", status, _responseText, _headers);
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<void>(<any>null);
}
/**
* Bring all devices online
* @return Message sent
*/
onlineall(): Promise<void> {
let url_ = this.baseUrl + "/online";
url_ = url_.replace(/[?&]$/, "");
let options_ = <RequestInit>{
method: "POST",
headers: {
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processOnlineall(_response);
});
}
protected processOnlineall(response: Response): Promise<void> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
return response.text().then((_responseText) => {
return;
});
} else if (status === 500) {
return response.text().then((_responseText) => {
return throwException("Message sending unsuccessful", status, _responseText, _headers);
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<void>(<any>null);
}
/**
* Get all device info
* @param deviceID ID of device to query
* @return Information about a particular device
*/
getdevice(deviceID: string): Promise<Device> {
let url_ = this.baseUrl + "/{deviceID}";
if (deviceID === undefined || deviceID === null)
throw new Error("The parameter 'deviceID' must be defined.");
url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID));
url_ = url_.replace(/[?&]$/, "");
let options_ = <RequestInit>{
method: "GET",
headers: {
"Accept": "application/json",
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processGetdevice(_response);
});
}
protected processGetdevice(response: Response): Promise<Device> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
return response.text().then((_responseText) => {
let result200: any = null;
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
result200 = Device.fromJS(resultData200);
return result200;
});
} else if (status === 404) {
return response.text().then((_responseText) => {
return throwException("Device not found", status, _responseText, _headers);
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<Device>(<any>null);
}
/**
* Shut down device
* @param deviceID ID of device to shut down
* @return Message sent
*/
offlinedevice(deviceID: string): Promise<void> {
let url_ = this.baseUrl + "/{deviceID}/offline";
if (deviceID === undefined || deviceID === null)
throw new Error("The parameter 'deviceID' must be defined.");
url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID));
url_ = url_.replace(/[?&]$/, "");
let options_ = <RequestInit>{
method: "POST",
headers: {
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processOfflinedevice(_response);
});
}
protected processOfflinedevice(response: Response): Promise<void> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
return response.text().then((_responseText) => {
return;
});
} else if (status === 500) {
return response.text().then((_responseText) => {
return throwException("Message sending unsuccessful", status, _responseText, _headers);
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<void>(<any>null);
}
/**
* Bring device online
* @param deviceID ID of device to bring online
* @return Message sent
*/
onlinedevice(deviceID: string): Promise<void> {
let url_ = this.baseUrl + "/{deviceID}/online";
if (deviceID === undefined || deviceID === null)
throw new Error("The parameter 'deviceID' must be defined.");
url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID));
url_ = url_.replace(/[?&]$/, "");
let options_ = <RequestInit>{
method: "POST",
headers: {
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processOnlinedevice(_response);
});
}
protected processOnlinedevice(response: Response): Promise<void> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
return response.text().then((_responseText) => {
return;
});
} else if (status === 500) {
return response.text().then((_responseText) => {
return throwException("Message sending unsuccessful", status, _responseText, _headers);
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<void>(<any>null);
}
/**
* Get info about a particular device's sensor
* @param deviceID ID of device to query
* @param sensorID ID of sensor to query
* @return Information about a sensor
*/
getsensor(deviceID: string, sensorID: string): Promise<Sensor> {
let url_ = this.baseUrl + "/{deviceID}/{sensorID}";
if (deviceID === undefined || deviceID === null)
throw new Error("The parameter 'deviceID' must be defined.");
url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID));
if (sensorID === undefined || sensorID === null)
throw new Error("The parameter 'sensorID' must be defined.");
url_ = url_.replace("{sensorID}", encodeURIComponent("" + sensorID));
url_ = url_.replace(/[?&]$/, "");
let options_ = <RequestInit>{
method: "GET",
headers: {
"Accept": "application/json",
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processGetsensor(_response);
});
}
protected processGetsensor(response: Response): Promise<Sensor> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
return response.text().then((_responseText) => {
let result200: any = null;
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
result200 = Sensor.fromJS(resultData200);
return result200;
});
} else if (status === 404) {
return response.text().then((_responseText) => {
return throwException("Device or sensor not found", status, _responseText, _headers);
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<Sensor>(<any>null);
}
/**
* Shut down sensor
* @param deviceID ID of device to query
* @param sensorID ID of sensor to query
* @return Message sent
*/
offlinesensor(deviceID: string, sensorID: string): Promise<void> {
let url_ = this.baseUrl + "/{deviceID}/{sensorID}/offline";
if (deviceID === undefined || deviceID === null)
throw new Error("The parameter 'deviceID' must be defined.");
url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID));
if (sensorID === undefined || sensorID === null)
throw new Error("The parameter 'sensorID' must be defined.");
url_ = url_.replace("{sensorID}", encodeURIComponent("" + sensorID));
url_ = url_.replace(/[?&]$/, "");
let options_ = <RequestInit>{
method: "POST",
headers: {
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processOfflinesensor(_response);
});
}
protected processOfflinesensor(response: Response): Promise<void> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
return response.text().then((_responseText) => {
return;
});
} else if (status === 500) {
return response.text().then((_responseText) => {
return throwException("Message sending unsuccessful", status, _responseText, _headers);
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<void>(<any>null);
}
/**
* Bring sensor online
* @param deviceID ID of device to query
* @param sensorID ID of sensor to query
* @return Message sent
*/
onlinesensor(deviceID: string, sensorID: string): Promise<void> {
let url_ = this.baseUrl + "/{deviceID}/{sensorID}/online";
if (deviceID === undefined || deviceID === null)
throw new Error("The parameter 'deviceID' must be defined.");
url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID));
if (sensorID === undefined || sensorID === null)
throw new Error("The parameter 'sensorID' must be defined.");
url_ = url_.replace("{sensorID}", encodeURIComponent("" + sensorID));
url_ = url_.replace(/[?&]$/, "");
let options_ = <RequestInit>{
method: "POST",
headers: {
'Authorization': sessionStorage.getItem('user')
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processOnlinesensor(_response);
});
}
protected processOnlinesensor(response: Response): Promise<void> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
return response.text().then((_responseText) => {
return;
});
} else if (status === 500) {
return response.text().then((_responseText) => {
return throwException("Message sending unsuccessful", status, _responseText, _headers);
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<void>(<any>null);
}
}
export class Device implements IDevice {
id!: string;
status!: DeviceStatus;
url!: string;
coordinates!: Coordinates;
sensors!: Sensor[];
constructor(data?: IDevice) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
if (!data) {
this.coordinates = new Coordinates();
this.sensors = [];
}
}
init(_data?: any) {
if (_data) {
this.id = _data["id"];
this.status = _data["status"];
this.url = _data["url"];
this.coordinates = _data["coordinates"] ? Coordinates.fromJS(_data["coordinates"]) : new Coordinates();
if (Array.isArray(_data["sensors"])) {
this.sensors = [] as any;
for (let item of _data["sensors"])
this.sensors!.push(Sensor.fromJS(item));
}
}
}
static fromJS(data: any): Device {
data = typeof data === 'object' ? data : {};
let result = new Device();
result.init(data);
return result;
}
toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["id"] = this.id;
data["status"] = this.status;
data["url"] = this.url;
data["coordinates"] = this.coordinates ? this.coordinates.toJSON() : <any>undefined;
if (Array.isArray(this.sensors)) {
data["sensors"] = [];
for (let item of this.sensors)
data["sensors"].push(item.toJSON());
}
return data;
}
}
export interface IDevice {
id: string;
status: DeviceStatus;
url: string;
coordinates: Coordinates;
sensors: Sensor[];
}
export class Sensor implements ISensor {
id!: string;
status!: SensorStatus;
constructor(data?: ISensor) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
init(_data?: any) {
if (_data) {
this.id = _data["id"];
this.status = _data["status"];
}
}
static fromJS(data: any): Sensor {
data = typeof data === 'object' ? data : {};
let result = new Sensor();
result.init(data);
return result;
}
toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["id"] = this.id;
data["status"] = this.status;
return data;
}
}
export interface ISensor {
id: string;
status: SensorStatus;
}
export enum DeviceStatus {
Online = "online",
Error = "error",
Offline = "offline",
}
export class Coordinates implements ICoordinates {
latitude!: number;
longitude!: number;
constructor(data?: ICoordinates) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
init(_data?: any) {
if (_data) {
this.latitude = _data["latitude"];
this.longitude = _data["longitude"];
}
}
static fromJS(data: any): Coordinates {
data = typeof data === 'object' ? data : {};
let result = new Coordinates();
result.init(data);
return result;
}
toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["latitude"] = this.latitude;
data["longitude"] = this.longitude;
return data;
}
}
export interface ICoordinates {
latitude: number;
longitude: number;
}
export enum SensorStatus {
Online = "online",
Unknown = "unknown",
Offline = "offline",
}
export class ApiException extends Error {
message: string;
status: number;
response: string;
headers: { [key: string]: any; };
result: any;
constructor(message: string, status: number, response: string, headers: { [key: string]: any; }, result: any) {
super();
this.message = message;
this.status = status;
this.response = response;
this.headers = headers;
this.result = result;
}
protected isApiException = true;
static isApiException(obj: any): obj is ApiException {
return obj.isApiException === true;
}
}
function throwException(message: string, status: number, response: string, headers: { [key: string]: any; }, result?: any): any {
if (result !== null && result !== undefined)
throw result;
else
throw new ApiException(message, status, response, headers, null);
}

View File

@ -1,14 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ErrorDispatcher = {
errorHandlers: [],
registerErrorHandler: function (errorHandlerFn) {
this.errorHandlers.push(errorHandlerFn);
},
raiseError: function (errorMessage) {
for (var i = 0; i < this.errorHandlers.length; i++)
this.errorHandlers[i](errorMessage);
}
};
exports.default = ErrorDispatcher;
//# sourceMappingURL=ErrorDispatcher.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"ErrorDispatcher.js","sourceRoot":"","sources":["ErrorDispatcher.ts"],"names":[],"mappings":";;AAAA,IAAM,eAAe,GAAG;IACtB,aAAa,EAAE,EAAE;IAEjB,oBAAoB,YAAC,cAAc;QACjC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC1C,CAAC;IAED,UAAU,YAAC,YAAY;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE;YAChD,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IACxC,CAAC;CACF,CAAC;AAEF,kBAAe,eAAe,CAAC"}

View File

@ -1,14 +0,0 @@
const ErrorDispatcher = {
errorHandlers: [],
registerErrorHandler(errorHandlerFn) {
this.errorHandlers.push(errorHandlerFn);
},
raiseError(errorMessage) {
for (let i = 0; i < this.errorHandlers.length; i++)
this.errorHandlers[i](errorMessage);
}
};
export default ErrorDispatcher;

View File

@ -1,50 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ErrorDispatcher_1 = require("./ErrorDispatcher");
function get(url) {
var options = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': sessionStorage.getItem('user')
}
};
return makeRequest(url, options);
}
function post(url, request) {
var options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': sessionStorage.getItem('user')
},
body: "",
};
if (request)
options.body = JSON.stringify(request);
return makeRequest(url, options);
}
function makeRequest(url, options) {
return fetch(url, options)
.then(ensureResponseSuccess)
.catch(errorHandler);
}
function ensureResponseSuccess(response) {
if (!response.ok)
return response.json()
.then(function (data) { return errorHandler(data); });
return response.text()
.then(function (text) { return text.length ? JSON.parse(text) : {}; });
}
function errorHandler(response) {
console.log(response);
if (response && response.Error)
ErrorDispatcher_1.default.raiseError(response.Error);
return Promise.reject();
}
exports.default = {
get: get,
post: post,
makeRequest: makeRequest
};
//# sourceMappingURL=ServiceBase.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"ServiceBase.js","sourceRoot":"","sources":["ServiceBase.ts"],"names":[],"mappings":";;AAAA,qDAAgD;AAEhD,SAAS,GAAG,CAAC,GAAW;IACpB,IAAI,OAAO,GAAG;QACV,MAAM,EAAE,KAAK;QACb,OAAO,EAAE;YACL,cAAc,EAAE,kBAAkB;YAClC,eAAe,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;SAClD;KACJ,CAAC;IAEF,OAAO,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,IAAI,CAAC,GAAW,EAAE,OAAY;IACnC,IAAI,OAAO,GAAG;QACV,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACL,cAAc,EAAE,kBAAkB;YAClC,eAAe,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;SAClD;QACD,IAAI,EAAE,EAAE;KACX,CAAC;IAEF,IAAI,OAAO;QACP,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAE3C,OAAO,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,WAAW,CAAC,GAAW,EAAE,OAAY;IAC1C,OAAO,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC;SACrB,IAAI,CAAC,qBAAqB,CAAC;SAC3B,KAAK,CAAC,YAAY,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,qBAAqB,CAAC,QAAa;IACxC,IAAI,CAAC,QAAQ,CAAC,EAAE;QACZ,OAAO,QAAQ,CAAC,IAAI,EAAE;aACjB,IAAI,CAAC,UAAC,IAAS,IAAK,OAAA,YAAY,CAAC,IAAI,CAAC,EAAlB,CAAkB,CAAC,CAAC;IAEjD,OAAO,QAAQ,CAAC,IAAI,EAAE;SACjB,IAAI,CAAC,UAAC,IAAS,IAAK,OAAA,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAnC,CAAmC,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,YAAY,CAAC,QAAa;IAC/B,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAEtB,IAAI,QAAQ,IAAI,QAAQ,CAAC,KAAK;QAC1B,yBAAe,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE/C,OAAO,OAAO,CAAC,MAAM,EAAE,CAAC;AAC5B,CAAC;AAED,kBAAe;IACX,GAAG,KAAA;IACH,IAAI,MAAA;IACJ,WAAW,aAAA;CACd,CAAC"}

View File

@ -1,59 +0,0 @@
import ErrorDispatcher from './ErrorDispatcher';
function get(url: string) {
let options = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': sessionStorage.getItem('user')
}
};
return makeRequest(url, options);
}
function post(url: string, request: any) {
let options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': sessionStorage.getItem('user')
},
body: "",
};
if (request)
options.body = JSON.stringify(request);
return makeRequest(url, options);
}
function makeRequest(url: string, options: any) {
return fetch(url, options)
.then(ensureResponseSuccess)
.catch(errorHandler);
}
function ensureResponseSuccess(response: any) {
if (!response.ok)
return response.json()
.then((data: any) => errorHandler(data));
return response.text()
.then((text: any) => text.length ? JSON.parse(text) : {});
}
function errorHandler(response: any) {
console.log(response);
if (response && response.Error)
ErrorDispatcher.raiseError(response.Error);
return Promise.reject();
}
export default {
get,
post,
makeRequest
};

View File

@ -5,6 +5,7 @@ import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
import AuthService from './AuthService';
export default function Auth(props: any) {
props.onAuthenticated();
const history = useHistory();
const classes = useStyles();
@ -36,7 +37,6 @@ export default function Auth(props: any) {
};
const onLoginClicked = () => {
setIsLoggingIn(true);
if (!username) {
setShowError(true);
@ -52,15 +52,16 @@ export default function Auth(props: any) {
return;
}
setIsLoggingIn(true);
AuthService.login(username, password)
.then(() => {
setIsLoggingIn(false);
props.onAuthenticated();
history.push('/');
}).catch(() => {
setShowError(true);
setErrorMessage('Invalid credentials');
}).finally(() => {
setIsLoggingIn(false);
setErrorMessage('Invalid credentials');
});
};
@ -86,7 +87,7 @@ export default function Auth(props: any) {
</Typography>
</Grid>
<Grid item xs={12} >
<TextField label="Username" type="text" onChange={onUsernameChanged} />
<TextField autoFocus label="Username" type="text" onChange={onUsernameChanged} />
</Grid>
<Grid item xs={12} >
<TextField label="Password" type="password" onChange={onPasswordChanged} onKeyPress={onPasswordKeyPress} />

View File

@ -0,0 +1,256 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ApiException = exports.RegisterRequest = exports.AuthenticateRequest = exports.HttpStatusCode = void 0;
var AuthClient = /** @class */ (function () {
function AuthClient(baseUrl, http) {
this.jsonParseReviver = undefined;
this.http = http ? http : window;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "";
}
AuthClient.prototype.authenticate = function (model) {
var _this = this;
var url_ = this.baseUrl + "/api/Auth/authenticate";
url_ = url_.replace(/[?&]$/, "");
var content_ = JSON.stringify(model);
var options_ = {
body: content_,
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
}
};
return this.http.fetch(url_, options_).then(function (_response) {
return _this.processAuthenticate(_response);
});
};
AuthClient.prototype.processAuthenticate = function (response) {
var _this = this;
var status = response.status;
var _headers = {};
if (response.headers && response.headers.forEach) {
response.headers.forEach(function (v, k) { return _headers[k] = v; });
}
;
if (status === 200) {
return response.text().then(function (_responseText) {
var result200 = null;
var resultData200 = _responseText === "" ? null : JSON.parse(_responseText, _this.jsonParseReviver);
result200 = resultData200 !== undefined ? resultData200 : null;
return result200;
});
}
else if (status !== 200 && status !== 204) {
return response.text().then(function (_responseText) {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve(null);
};
AuthClient.prototype.register = function (model) {
var _this = this;
var url_ = this.baseUrl + "/api/Auth/register";
url_ = url_.replace(/[?&]$/, "");
var content_ = JSON.stringify(model);
var options_ = {
body: content_,
method: "POST",
headers: {
"Content-Type": "application/json",
}
};
return this.http.fetch(url_, options_).then(function (_response) {
return _this.processRegister(_response);
});
};
AuthClient.prototype.processRegister = function (response) {
var status = response.status;
var _headers = {};
if (response.headers && response.headers.forEach) {
response.headers.forEach(function (v, k) { return _headers[k] = v; });
}
;
if (status === 204) {
return response.text().then(function (_responseText) {
return;
});
}
else if (status !== 200 && status !== 204) {
return response.text().then(function (_responseText) {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve(null);
};
return AuthClient;
}());
exports.default = AuthClient;
var HttpStatusCode;
(function (HttpStatusCode) {
HttpStatusCode["Continue"] = "Continue";
HttpStatusCode["SwitchingProtocols"] = "SwitchingProtocols";
HttpStatusCode["Processing"] = "Processing";
HttpStatusCode["EarlyHints"] = "EarlyHints";
HttpStatusCode["OK"] = "OK";
HttpStatusCode["Created"] = "Created";
HttpStatusCode["Accepted"] = "Accepted";
HttpStatusCode["NonAuthoritativeInformation"] = "NonAuthoritativeInformation";
HttpStatusCode["NoContent"] = "NoContent";
HttpStatusCode["ResetContent"] = "ResetContent";
HttpStatusCode["PartialContent"] = "PartialContent";
HttpStatusCode["MultiStatus"] = "MultiStatus";
HttpStatusCode["AlreadyReported"] = "AlreadyReported";
HttpStatusCode["IMUsed"] = "IMUsed";
HttpStatusCode["MultipleChoices"] = "Ambiguous";
HttpStatusCode["Ambiguous"] = "Ambiguous";
HttpStatusCode["MovedPermanently"] = "Moved";
HttpStatusCode["Moved"] = "Moved";
HttpStatusCode["Found"] = "Redirect";
HttpStatusCode["Redirect"] = "Redirect";
HttpStatusCode["SeeOther"] = "RedirectMethod";
HttpStatusCode["RedirectMethod"] = "RedirectMethod";
HttpStatusCode["NotModified"] = "NotModified";
HttpStatusCode["UseProxy"] = "UseProxy";
HttpStatusCode["Unused"] = "Unused";
HttpStatusCode["TemporaryRedirect"] = "TemporaryRedirect";
HttpStatusCode["RedirectKeepVerb"] = "TemporaryRedirect";
HttpStatusCode["PermanentRedirect"] = "PermanentRedirect";
HttpStatusCode["BadRequest"] = "BadRequest";
HttpStatusCode["Unauthorized"] = "Unauthorized";
HttpStatusCode["PaymentRequired"] = "PaymentRequired";
HttpStatusCode["Forbidden"] = "Forbidden";
HttpStatusCode["NotFound"] = "NotFound";
HttpStatusCode["MethodNotAllowed"] = "MethodNotAllowed";
HttpStatusCode["NotAcceptable"] = "NotAcceptable";
HttpStatusCode["ProxyAuthenticationRequired"] = "ProxyAuthenticationRequired";
HttpStatusCode["RequestTimeout"] = "RequestTimeout";
HttpStatusCode["Conflict"] = "Conflict";
HttpStatusCode["Gone"] = "Gone";
HttpStatusCode["LengthRequired"] = "LengthRequired";
HttpStatusCode["PreconditionFailed"] = "PreconditionFailed";
HttpStatusCode["RequestEntityTooLarge"] = "RequestEntityTooLarge";
HttpStatusCode["RequestUriTooLong"] = "RequestUriTooLong";
HttpStatusCode["UnsupportedMediaType"] = "UnsupportedMediaType";
HttpStatusCode["RequestedRangeNotSatisfiable"] = "RequestedRangeNotSatisfiable";
HttpStatusCode["ExpectationFailed"] = "ExpectationFailed";
HttpStatusCode["MisdirectedRequest"] = "MisdirectedRequest";
HttpStatusCode["UnprocessableEntity"] = "UnprocessableEntity";
HttpStatusCode["Locked"] = "Locked";
HttpStatusCode["FailedDependency"] = "FailedDependency";
HttpStatusCode["UpgradeRequired"] = "UpgradeRequired";
HttpStatusCode["PreconditionRequired"] = "PreconditionRequired";
HttpStatusCode["TooManyRequests"] = "TooManyRequests";
HttpStatusCode["RequestHeaderFieldsTooLarge"] = "RequestHeaderFieldsTooLarge";
HttpStatusCode["UnavailableForLegalReasons"] = "UnavailableForLegalReasons";
HttpStatusCode["InternalServerError"] = "InternalServerError";
HttpStatusCode["NotImplemented"] = "NotImplemented";
HttpStatusCode["BadGateway"] = "BadGateway";
HttpStatusCode["ServiceUnavailable"] = "ServiceUnavailable";
HttpStatusCode["GatewayTimeout"] = "GatewayTimeout";
HttpStatusCode["HttpVersionNotSupported"] = "HttpVersionNotSupported";
HttpStatusCode["VariantAlsoNegotiates"] = "VariantAlsoNegotiates";
HttpStatusCode["InsufficientStorage"] = "InsufficientStorage";
HttpStatusCode["LoopDetected"] = "LoopDetected";
HttpStatusCode["NotExtended"] = "NotExtended";
HttpStatusCode["NetworkAuthenticationRequired"] = "NetworkAuthenticationRequired";
})(HttpStatusCode = exports.HttpStatusCode || (exports.HttpStatusCode = {}));
var AuthenticateRequest = /** @class */ (function () {
function AuthenticateRequest(data) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
this[property] = data[property];
}
}
}
AuthenticateRequest.prototype.init = function (_data) {
if (_data) {
this.username = _data["username"];
this.password = _data["password"];
}
};
AuthenticateRequest.fromJS = function (data) {
data = typeof data === 'object' ? data : {};
var result = new AuthenticateRequest();
result.init(data);
return result;
};
AuthenticateRequest.prototype.toJSON = function (data) {
data = typeof data === 'object' ? data : {};
data["username"] = this.username;
data["password"] = this.password;
return data;
};
return AuthenticateRequest;
}());
exports.AuthenticateRequest = AuthenticateRequest;
var RegisterRequest = /** @class */ (function () {
function RegisterRequest(data) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
this[property] = data[property];
}
}
}
RegisterRequest.prototype.init = function (_data) {
if (_data) {
this.username = _data["username"];
this.password = _data["password"];
this.confirmPassword = _data["confirmPassword"];
}
};
RegisterRequest.fromJS = function (data) {
data = typeof data === 'object' ? data : {};
var result = new RegisterRequest();
result.init(data);
return result;
};
RegisterRequest.prototype.toJSON = function (data) {
data = typeof data === 'object' ? data : {};
data["username"] = this.username;
data["password"] = this.password;
data["confirmPassword"] = this.confirmPassword;
return data;
};
return RegisterRequest;
}());
exports.RegisterRequest = RegisterRequest;
var ApiException = /** @class */ (function (_super) {
__extends(ApiException, _super);
function ApiException(message, status, response, headers, result) {
var _this = _super.call(this) || this;
_this.isApiException = true;
_this.message = message;
_this.status = status;
_this.response = response;
_this.headers = headers;
_this.result = result;
return _this;
}
ApiException.isApiException = function (obj) {
return obj.isApiException === true;
};
return ApiException;
}(Error));
exports.ApiException = ApiException;
function throwException(message, status, response, headers, result) {
if (result !== null && result !== undefined)
throw result;
else
throw new ApiException(message, status, response, headers, null);
}
//# sourceMappingURL=AuthClient.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,274 @@
export default class AuthClient {
private http: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> };
private baseUrl: string;
protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined;
constructor(baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
this.http = http ? http : <any>window;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "";
}
authenticate(model: AuthenticateRequest): Promise<any> {
let url_ = this.baseUrl + "/api/Auth/authenticate";
url_ = url_.replace(/[?&]$/, "");
const content_ = JSON.stringify(model);
let options_ = <RequestInit>{
body: content_,
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processAuthenticate(_response);
});
}
protected processAuthenticate(response: Response): Promise<any> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
return response.text().then((_responseText) => {
let result200: any = null;
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
result200 = resultData200 !== undefined ? resultData200 : <any>null;
return result200;
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<any>(<any>null);
}
register(model: RegisterRequest): Promise<void> {
let url_ = this.baseUrl + "/api/Auth/register";
url_ = url_.replace(/[?&]$/, "");
const content_ = JSON.stringify(model);
let options_ = <RequestInit>{
body: content_,
method: "POST",
headers: {
"Content-Type": "application/json",
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processRegister(_response);
});
}
protected processRegister(response: Response): Promise<void> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 204) {
return response.text().then((_responseText) => {
return;
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<void>(<any>null);
}
}
export enum HttpStatusCode {
Continue = "Continue",
SwitchingProtocols = "SwitchingProtocols",
Processing = "Processing",
EarlyHints = "EarlyHints",
OK = "OK",
Created = "Created",
Accepted = "Accepted",
NonAuthoritativeInformation = "NonAuthoritativeInformation",
NoContent = "NoContent",
ResetContent = "ResetContent",
PartialContent = "PartialContent",
MultiStatus = "MultiStatus",
AlreadyReported = "AlreadyReported",
IMUsed = "IMUsed",
MultipleChoices = "Ambiguous",
Ambiguous = "Ambiguous",
MovedPermanently = "Moved",
Moved = "Moved",
Found = "Redirect",
Redirect = "Redirect",
SeeOther = "RedirectMethod",
RedirectMethod = "RedirectMethod",
NotModified = "NotModified",
UseProxy = "UseProxy",
Unused = "Unused",
TemporaryRedirect = "TemporaryRedirect",
RedirectKeepVerb = "TemporaryRedirect",
PermanentRedirect = "PermanentRedirect",
BadRequest = "BadRequest",
Unauthorized = "Unauthorized",
PaymentRequired = "PaymentRequired",
Forbidden = "Forbidden",
NotFound = "NotFound",
MethodNotAllowed = "MethodNotAllowed",
NotAcceptable = "NotAcceptable",
ProxyAuthenticationRequired = "ProxyAuthenticationRequired",
RequestTimeout = "RequestTimeout",
Conflict = "Conflict",
Gone = "Gone",
LengthRequired = "LengthRequired",
PreconditionFailed = "PreconditionFailed",
RequestEntityTooLarge = "RequestEntityTooLarge",
RequestUriTooLong = "RequestUriTooLong",
UnsupportedMediaType = "UnsupportedMediaType",
RequestedRangeNotSatisfiable = "RequestedRangeNotSatisfiable",
ExpectationFailed = "ExpectationFailed",
MisdirectedRequest = "MisdirectedRequest",
UnprocessableEntity = "UnprocessableEntity",
Locked = "Locked",
FailedDependency = "FailedDependency",
UpgradeRequired = "UpgradeRequired",
PreconditionRequired = "PreconditionRequired",
TooManyRequests = "TooManyRequests",
RequestHeaderFieldsTooLarge = "RequestHeaderFieldsTooLarge",
UnavailableForLegalReasons = "UnavailableForLegalReasons",
InternalServerError = "InternalServerError",
NotImplemented = "NotImplemented",
BadGateway = "BadGateway",
ServiceUnavailable = "ServiceUnavailable",
GatewayTimeout = "GatewayTimeout",
HttpVersionNotSupported = "HttpVersionNotSupported",
VariantAlsoNegotiates = "VariantAlsoNegotiates",
InsufficientStorage = "InsufficientStorage",
LoopDetected = "LoopDetected",
NotExtended = "NotExtended",
NetworkAuthenticationRequired = "NetworkAuthenticationRequired",
}
export class AuthenticateRequest implements IAuthenticateRequest {
username!: string;
password!: string;
constructor(data?: IAuthenticateRequest) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
init(_data?: any) {
if (_data) {
this.username = _data["username"];
this.password = _data["password"];
}
}
static fromJS(data: any): AuthenticateRequest {
data = typeof data === 'object' ? data : {};
let result = new AuthenticateRequest();
result.init(data);
return result;
}
toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["username"] = this.username;
data["password"] = this.password;
return data;
}
}
export interface IAuthenticateRequest {
username: string;
password: string;
}
export class RegisterRequest implements IRegisterRequest {
username!: string;
password!: string;
confirmPassword!: string;
constructor(data?: IRegisterRequest) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
init(_data?: any) {
if (_data) {
this.username = _data["username"];
this.password = _data["password"];
this.confirmPassword = _data["confirmPassword"];
}
}
static fromJS(data: any): RegisterRequest {
data = typeof data === 'object' ? data : {};
let result = new RegisterRequest();
result.init(data);
return result;
}
toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["username"] = this.username;
data["password"] = this.password;
data["confirmPassword"] = this.confirmPassword;
return data;
}
}
export interface IRegisterRequest {
username: string;
password: string;
confirmPassword: string;
}
export interface FileResponse {
data: Blob;
status: number;
fileName?: string;
headers?: { [name: string]: any };
}
export class ApiException extends Error {
message: string;
status: number;
response: string;
headers: { [key: string]: any; };
result: any;
constructor(message: string, status: number, response: string, headers: { [key: string]: any; }, result: any) {
super();
this.message = message;
this.status = status;
this.response = response;
this.headers = headers;
this.result = result;
}
protected isApiException = true;
static isApiException(obj: any): obj is ApiException {
return obj.isApiException === true;
}
}
function throwException(message: string, status: number, response: string, headers: { [key: string]: any; }, result?: any): any {
if (result !== null && result !== undefined)
throw result;
else
throw new ApiException(message, status, response, headers, null);
}

View File

@ -1,30 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ServiceBase_1 = require("../../common/ServiceBase");
var login_url = 'api/auth/authenticate';
var AuthClient_1 = require("./AuthClient");
exports.default = {
isAuthenticated: function () {
return sessionStorage.getItem('user') !== null;
return sessionStorage.getItem('user') !== null && sessionStorage.getItem('user') !== undefined;
},
isAdmin: function () {
return sessionStorage.getItem('role') === 'Admin';
},
logout: function () {
sessionStorage.removeItem('user');
sessionStorage.removeItem('role');
},
login: function (username, password) {
var body = {
var service = new AuthClient_1.default();
var request = new AuthClient_1.AuthenticateRequest({
username: username,
password: password
};
var options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
};
return ServiceBase_1.default.makeRequest(login_url, options)
});
return service.authenticate(request)
.then(function (response) {
sessionStorage.setItem('user', response.token_type + " " + response.access_token);
sessionStorage.setItem('role', response.role);
//console.log(response);
sessionStorage.setItem('user', response.tokenType + " " + response.accessToken);
sessionStorage.setItem('role', response.userRole);
return Promise.resolve();
});
}

View File

@ -1 +1 @@
{"version":3,"file":"AuthService.js","sourceRoot":"","sources":["AuthService.ts"],"names":[],"mappings":";;AAAA,wDAAmD;AAEnD,IAAM,SAAS,GAAG,uBAAuB,CAAC;AAE1C,kBAAe;IACX,eAAe;QACX,OAAO,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IACnD,CAAC;IAED,OAAO;QACH,OAAO,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC;IACtD,CAAC;IAED,KAAK,EAAL,UAAM,QAAgB,EAAE,QAAgB;QACpC,IAAI,IAAI,GAAG;YACP,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,QAAQ;SACrB,CAAC;QACF,IAAI,OAAO,GAAG;YACV,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACL,cAAc,EAAE,kBAAkB;aACrC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC7B,CAAC;QAEF,OAAO,qBAAW,CAAC,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC;aAC7C,IAAI,CAAC,UAAA,QAAQ;YACV,cAAc,CAAC,OAAO,CAAC,MAAM,EAAK,QAAQ,CAAC,UAAU,SAAI,QAAQ,CAAC,YAAc,CAAC,CAAC;YAClF,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC9C,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC;IACX,CAAC;CACJ,CAAA"}
{"version":3,"file":"AuthService.js","sourceRoot":"","sources":["AuthService.ts"],"names":[],"mappings":";;AAAA,2CAA+D;AAE/D,kBAAe;IACX,eAAe;QACX,OAAO,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,SAAS,CAAC;IACnG,CAAC;IAED,OAAO;QACH,OAAO,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC;IACtD,CAAC;IAED,MAAM;QACF,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAClC,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,EAAL,UAAM,QAAgB,EAAE,QAAgB;QACpC,IAAM,OAAO,GAAG,IAAI,oBAAU,EAAE,CAAC;QAEjC,IAAI,OAAO,GAAG,IAAI,gCAAmB,CAAC;YAClC,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,QAAQ;SACrB,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC;aAC/B,IAAI,CAAC,UAAA,QAAQ;YACV,wBAAwB;YACxB,cAAc,CAAC,OAAO,CAAC,MAAM,EAAK,QAAQ,CAAC,SAAS,SAAI,QAAQ,CAAC,WAAa,CAAC,CAAC;YAChF,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAClD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC;IACX,CAAC;CACJ,CAAA"}

View File

@ -1,33 +1,32 @@
import ServiceBase from '../../common/ServiceBase';
const login_url = 'api/auth/authenticate';
import AuthClient, { AuthenticateRequest } from './AuthClient';
export default {
isAuthenticated() {
return sessionStorage.getItem('user') !== null;
return sessionStorage.getItem('user') !== null && sessionStorage.getItem('user') !== undefined;
},
isAdmin() {
return sessionStorage.getItem('role') === 'Admin';
},
logout() {
sessionStorage.removeItem('user');
sessionStorage.removeItem('role');
},
login(username: string, password: string) {
let body = {
const service = new AuthClient();
let request = new AuthenticateRequest({
username: username,
password: password
};
let options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
};
});
return ServiceBase.makeRequest(login_url, options)
return service.authenticate(request)
.then(response => {
sessionStorage.setItem('user', `${response.token_type} ${response.access_token}`);
sessionStorage.setItem('role', response.role);
//console.log(response);
sessionStorage.setItem('user', `${response.tokenType} ${response.accessToken}`);
sessionStorage.setItem('role', response.userRole);
return Promise.resolve();
});
}

View File

@ -0,0 +1,191 @@
import React, { Component } from 'react';
import Accordion from '@material-ui/core/Accordion';
import { blue, blueGrey, green, orange, red, yellow } from '@material-ui/core/colors';
import AccordionSummary from '@material-ui/core/AccordionSummary';
import AccordionDetails from '@material-ui/core/AccordionDetails';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import { Grid, Typography, Paper, IconButton, Box, FormControlLabel } from '@material-ui/core';
import { withStyles } from '@material-ui/styles';
import { withRouter } from "react-router";
import { Power, PowerOff, Refresh } from '@material-ui/icons/';
import DeviceService from '../../common/DeviceService'
import DevicesContext from '../../contexts/DevicesContext';
const styles = theme => ({
acc_summary: {
backgroundColor: blueGrey[50],
},
acc_details: {
backgroundColor: blueGrey[100],
},
grid_typo: {
fontSize: theme.typography.pxToRem(20),
fontWeight: theme.typography.fontWeightRegular,
},
grid_typo_2: {
marginLeft: '5px',
fontSize: theme.typography.pxToRem(15),
fontWeight: theme.typography.fontWeightRegular,
color: theme.palette.text.secondary,
},
grid_item: {
width: '100%',
marginLeft: '5px',
},
grid_item_typo: {
fontSize: theme.typography.pxToRem(15),
fontWeight: theme.typography.fontWeightRegular,
},
grid_item_typo_2: {
marginLeft: '5px',
fontSize: theme.typography.pxToRem(15),
fontWeight: theme.typography.fontWeightRegular,
color: theme.palette.text.secondary,
},
icon_box: {
marginRight: '15px',
}
});
class DeviceComponent extends Component {
constructor(props) {
super(props);
this.state = {
expanded: "",
}
}
static contextType = DevicesContext;
getColor(status) {
if (status == "Online") {
return { color: green[600] };
} else if (status == "Offline") {
return { color: orange[900] };
} else /* if (device.status == "unknown") */ {
return { color: red[800] };
}
}
componentDidMount() {
const id = this.props.match.params.id;
this.setState({ expanded: id });
}
renderSensorButtons(device, sensor) {
var service = new DeviceService();
return this.renderButtons(
() => service.onlinesensor(device.id, sensor.id),
() => service.offlinesensor(device.id, sensor.id),
() => this.context.updateDevice(device.id)
);
}
renderDeviceButtons(device) {
var service = new DeviceService();
return this.renderButtons(
() => service.onlinedevice(device.id),
() => service.offlinedevice(device.id),
() => this.context.updateDevice(device.id)
);
}
renderButtons(onPower, onPowerOff, onRefresh) {
const renderOnOff = () => {
return (
<React.Fragment>
<IconButton color="primary" onClick={onPower}>
<Power />
</IconButton>
<IconButton color="primary" onClick={onPowerOff}>
<PowerOff />
</IconButton>
</React.Fragment>
);
}
const { classes } = this.props;
return (
<Box className={classes.icon_box}>
{this.props.isAdmin ? renderOnOff() : null}
<IconButton color="primary" onClick={onRefresh}>
<Refresh />
</IconButton>
</Box>
);
}
render() {
const { classes } = this.props;
const Sensors = this.props.device.sensors.map((sensor, index) => (
<Grid item className={classes.grid_item} key={sensor.id}>
<Grid container
spacing={3}
direction="row"
justify="space-between"
alignItems="center">
<Grid item>
<Typography className={classes.grid_item_typo}>Sensor {index}</Typography>
</Grid>
<Grid item>
<Typography className={classes.grid_item_typo_2}>{sensor.id}</Typography>
</Grid>
<Grid item>
<Typography style={this.getColor(sensor.status)}>Status: <b>{sensor.status}</b></Typography>
</Grid>
<Grid item>
{this.renderSensorButtons(this.props.device, sensor)}
</Grid>
</Grid>
</Grid>
));
const handleChange = (panel) => (event, isExpanded) => {
this.setState({ expanded: isExpanded ? panel : "" });
};
return (
<Accordion expanded={this.state.expanded === this.props.device.id} onChange={handleChange(this.props.device.id)}>
<AccordionSummary className={classes.acc_summary}
expandIcon={<ExpandMoreIcon />}
aria-controls={"device-panel-/" + this.props.device.id}
id={"device-panel-/" + this.props.device.id}>
<Grid container
spacing={3}
direction="row"
justify="space-between"
alignItems="center">
<Grid item>
<Typography className={classes.grid_typo}>Device {this.props.index}</Typography>
</Grid>
<Grid item>
<Typography className={classes.grid_typo_2}>{this.props.device.id}</Typography>
</Grid>
<Grid item>
<Typography style={this.getColor(this.props.device.status)}>Status: <b>{this.props.device.status}</b></Typography>
</Grid>
<Grid item>
<FormControlLabel
onClick={(event) => event.stopPropagation()}
onFocus={(event) => event.stopPropagation()}
control={this.renderDeviceButtons(this.props.device)}/>
</Grid>
</Grid>
</AccordionSummary>
<AccordionDetails className={classes.acc_details}>
<Grid className={classes.grid_item}
container
spacing={3}
direction="column"
justify="center"
alignItems="flex-start">
{Sensors}
</Grid>
</AccordionDetails>
</Accordion>
);
}
}
export default withRouter(withStyles(styles)(DeviceComponent));

View File

@ -0,0 +1,90 @@
import { Box, Paper, Typography, IconButton, Grid } from '@material-ui/core';
import { blue, blueGrey, green, orange, red, yellow } from '@material-ui/core/colors';
import { withStyles } from '@material-ui/styles';
import React from 'react';
import DeviceService from '../../common/DeviceService';
import DevicesContext from '../../contexts/DevicesContext';
import DeviceComponent from './DeviceComponent';
import { Power, PowerOff, Refresh } from '@material-ui/icons/';
const styles = theme => ({
root: {
padding: '64px',
backgroundColor: theme.palette.primary.dark,
},
paper: {
backgroundColor: blueGrey[50],
height: '60px',
margin: 'auto',
},
typo: {
fontSize: theme.typography.pxToRem(20),
fontWeight: theme.typography.fontWeightRegular,
},
});
class Devices extends React.Component {
constructor(props) {
super(props);
}
static contextType = DevicesContext;
componentDidMount() {
}
renderButtons() {
var service = new DeviceService();
const renderOnOff = () => {
return (
<React.Fragment>
<IconButton color="primary" onClick={() => service.onlineall()}>
<Power />
</IconButton>
<IconButton color="primary" onClick={() => service.offlineall()}>
<PowerOff />
</IconButton>
</React.Fragment>
);
}
return (
<Box>
{this.props.isAdmin ? renderOnOff() : null}
<IconButton color="primary" onClick={() => this.context.updateAllDevices()}>
<Refresh />
</IconButton>
</Box>
);
}
render() {
const { classes } = this.props;
const Devices = this.context.devices.map((device, index) => (
<DeviceComponent isAdmin={this.props.isAdmin} device={device} index={index} key={device.id}/>
));
return (
<Box className={classes.root}>
<Paper className={classes.paper} square>
<Grid container
spacing={3}
direction="row"
justify="center"
alignItems="center">
<Grid item>
<Typography className={classes.typo}>All Devices</Typography>
</Grid>
{this.renderButtons()}
<Grid item>
</Grid>
</Grid>
</Paper>
{Devices}
</Box>
);
}
}
export default withStyles(styles)(Devices);

View File

@ -0,0 +1,63 @@
import RadioButtonCheckedIcon from '@material-ui/icons/RadioButtonChecked';
import PlayCircleFilledIcon from '@material-ui/icons/PlayCircleFilled';
import { shadows } from '@material-ui/system';
import { Box, Popover, Typography, Tooltip, Grid } from '@material-ui/core';
import { blue, red, yellow } from '@material-ui/core/colors';
import React, { Component } from 'react';
import { useHistory, withRouter } from 'react-router-dom';
import { makeStyles } from '@material-ui/styles';
class DeviceMarker extends Component {
constructor(props) {
super(props);
this.state = {
AnchorEl: null
}
}
getColor() {
const { device } = this.props;
if (device.status == "Online") {
return { color: blue[800] };
} else if (device.status == "Offline") {
return { color: yellow[800] };
} else /* if (device.status == "unknown") */ {
return { color: red[800] };
}
}
useStyles() {
return makeStyles(theme => ({
root: {
display: 'grid'
},
icon: {
}
}));
}
render() {
const classes = this.useStyles(this.props);
const { device } = this.props;
const onClick = () => {
this.props.history.push('/devices/' + device.id)
};
const open = Boolean(this.state.AnchorEl);
return (
<Box className={classes.root} boxShadow={5}>
<Tooltip title={<div>ID: {device.id}<br />Status: {device.status}</div>} placement="top" leaveDelay={200} arrow>
<RadioButtonCheckedIcon fontSize="small" style={this.getColor()}
onClick={onClick}>
</RadioButtonCheckedIcon>
</Tooltip>
</Box>
);
}
}
export default withRouter(DeviceMarker);

View File

@ -0,0 +1,105 @@
/*global google*/
import GoogleMapReact from 'google-map-react';
import React, { Component } from 'react';
import DeviceMarker from './DeviceMarker'
import C from '../../common/Constants'
import DevicesContext from '../../contexts/DevicesContext';
const lat_offset = 0.000038;
const lng_offset = -0.000058;
export default class MapContainer extends Component {
constructor(props) {
super(props);
this.state = {
center: {
lat: 48.275939, lng: 21.469640
},
heatmapPoints: [],
};
this.probabilityHandler = this.probabilityHandler.bind(this);
}
static contextType = DevicesContext;
probabilityHandler(point) {
if (point.prob > 0.5) {
this.setState({
heatmapPoints: [...this.state.heatmapPoints, point]
});
if (this._googleMap !== undefined) {
const newPoint = { location: new google.maps.LatLng(point.lat, point.lng), weight: point.prob };
if (this._googleMap.heatmap !== null) {
this._googleMap.heatmap.data.push(newPoint)
}
}
}
}
componentDidMount() {
this.context.addHandler(C.probability_method_name, this.probabilityHandler);
const newPoints = [];
for (var p of this.context.heatmapPoints) {
if (p.prob > 0.5) {
newPoints.push(p)
}
}
this.setState({ heatmapPoints: newPoints });
}
componentWillUnmount() {
this.context.removeHandler(C.probability_method_name, this.probabilityHandler);
}
render() {
const heatMapData = {
positions: this.state.heatmapPoints,
options: {
radius: 50,
opacity: 0.6,
}
}
const mapOptions = {
disableDefaultUI: true,
zoomControl: true,
mapTypeControl: true,
overviewMapControl: true,
streetViewControl: false,
scaleControl: true,
mapTypeId: 'satellite'
}
const Markers = this.context.devices.map((device, index) => (
<DeviceMarker
key={device.id}
lat={device.coordinates.latitude + lat_offset}
lng={device.coordinates.longitude + lng_offset}
device={device}
/>
));
return (
<div style={{ height: '93vh', width: '100%' }}>
<GoogleMapReact
bootstrapURLKeys={{
key: ["AIzaSyCZ51VFfxqZ2GkCmVrcNZdUKsM0fuBQUCY"],
libraries: ['visualization']
}}
ref={(el) => this._googleMap = el}
options={mapOptions}
defaultZoom={18}
heatmapLibrary={true}
heatmap={heatMapData}
defaultCenter={this.state.center}>
{Markers}
</GoogleMapReact>
</div>
);
}
}

View File

@ -0,0 +1,12 @@
import React from 'react';
export default React.createContext({
devices: [],
heatmapPoints: [],
addHandler: (_, __) => { },
removeHandler: (_, __) => { },
updateDevice: () => { },
updateAllDevices: () => { },
});

View File

@ -0,0 +1,148 @@
import Context from './DevicesContext'
import { HubConnectionBuilder } from '@microsoft/signalr';
import DeviceService from '../common/DeviceService';
import C from '../common/Constants'
import React, { Component } from 'react'
const hub_url = '/hubs/devices';
export default class DevicesContextProvider extends Component {
constructor(props) {
super(props);
const handlers = {};
for (var property in C) {
handlers[C[property]] = [];
};
this.state = {
hubConnection: null,
devices: [],
heatmapPoints: [],
handlers: handlers,
};
}
addHandler = (methodName, handler) => {
const updatedHandlers = this.state.handlers;
updatedHandlers[methodName].push(handler);
//console.log("Added '" + methodName + "' handler.");
this.setState({ handlers: updatedHandlers });
}
removeHandler = (methodName, handler) => {
const updatedHandlers = this.state.handlers;
var index = updatedHandlers[methodName].findIndex((h => h === handler));
if (index > -1) {
updatedHandlers[methodName].splice(index, 1);
//console.log("Removed '" + methodName + "' handler.");
}
this.setState({ handlers: updatedHandlers });
}
updateDevice = (id) => {
this.updateDeviceInternal(id);
}
updateAllDevices = () => {
this.updateAllDevicesInternal();
}
invokeHandlers(methodName, context) {
this.state.handlers[methodName].forEach(function (handler) {
handler(context);
});
}
updateAllDevicesInternal(service = null) {
if (service === null) {
service = new DeviceService();
}
service.getall().then(result => {
this.setState({ devices: result });
}).catch(ex => {
console.log(ex);
});
}
updateDeviceInternal(id, service = null) {
if (service === null) {
service = new DeviceService();
}
service.getdevice(id).then(result => {
const updatedDevices = [...this.state.devices];
var index = updatedDevices.findIndex((d => d.id == id));
if (index > -1) {
updatedDevices[index] = result;
}
else {
updatedDevices.push(result);
}
this.setState({ devices: updatedDevices });
this.invokeHandlers(C.update_method_name, result);
}).catch(ex => console.log("Device update failed.", ex));
}
componentDidMount() {
const service = new DeviceService();
this.updateAllDevicesInternal(service);
const newConnection = new HubConnectionBuilder()
.withUrl(hub_url)
.withAutomaticReconnect()
.build();
this.setState({ hubConnection: newConnection });
newConnection.start()
.then(_ => {
console.log('Hub Connected!');
newConnection.on(C.probability_method_name, (id, date, prob) => {
//console.log(method_name + " recieved: [id: " + id + ", date: " + date + ", prob: " + prob + "]");
var device = this.state.devices.filter(function (x) { return x.id === id })[0]
var newPoint = { lat: device.coordinates.latitude, lng: device.coordinates.longitude, prob: prob, date: date };
this.setState({
heatmapPoints: [...this.state.heatmapPoints, newPoint]
});
this.invokeHandlers(C.probability_method_name, newPoint);
});
newConnection.on(C.update_all_method_name, () => {
this.updateAllDevicesInternal(service);
this.invokeHandlers(C.update_all_method_name, null);
});
newConnection.on(C.update_method_name, (id) => this.updateDeviceInternal(id, service));
}).catch(e => console.log('Hub Connection failed: ', e));
}
componentWillUnmount() {
if (this.state.hubConnection != null) {
this.state.hubConnection.off(C.probability_method_name);
this.state.hubConnection.off(C.update_all_method_name);
this.state.hubConnection.off(C.update_method_name);
console.log('Hub Disconnected!');
}
}
render() {
return (
<Context.Provider
value={{
devices: this.state.devices,
heatmapPoints: this.state.heatmapPoints,
addHandler: this.addHandler,
removeHandler: this.removeHandler,
updateDevice: this.updateDevice,
updateAllDevices: this.updateAllDevices,
}}
>
{this.props.children}
</Context.Provider>
);
};
}

View File

@ -35,8 +35,7 @@ namespace Birdmap.Controllers
}
[AllowAnonymous]
[HttpPost("authenticate")]
[ProducesResponseType(typeof(object), StatusCodes.Status200OK)]
[HttpPost("authenticate"), ProducesResponseType(typeof(object), StatusCodes.Status200OK)]
public async Task<IActionResult> AuthenticateAsync([FromBody] AuthenticateRequest model)
{
_logger.LogInformation($"Authenticating user [{model.Username}] with password [*******]...");
@ -70,8 +69,7 @@ namespace Birdmap.Controllers
}
[AllowAnonymous]
[HttpPost("register")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[HttpPost("register"), ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> RegisterAsync([FromBody] RegisterRequest model)
{
_logger.LogInformation($"Registering user [{model.Username}]...");

View File

@ -0,0 +1,161 @@
using Birdmap.BLL.Interfaces;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.Linq;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using Birdmap.API.Services.Hubs;
using Birdmap.API.Services;
namespace Birdmap.API.Controllers
{
[Authorize(Roles = "User, Admin")]
[ApiController]
[Route("api/[controller]")]
public class DevicesController : ControllerBase
{
private readonly IDeviceService _service;
private readonly IHubContext<DevicesHub, IDevicesHubClient> _hubContext;
private readonly ILogger<ServicesController> _logger;
public DevicesController(IDeviceService service, IHubContext<DevicesHub, IDevicesHubClient> hubContext, ILogger<ServicesController> logger)
{
_service = service;
_hubContext = hubContext;
_logger = logger;
}
/// <summary>Get all device info</summary>
/// <returns>Array of devices</returns>
[HttpGet]
public async Task<ActionResult<List<Device>>> Getall()
{
_logger.LogInformation("Getting all devices...");
return (await _service.GetallAsync()).ToList();
}
/// <summary>Shut down all devices</summary>
/// <returns>Message sent</returns>
[Authorize(Roles = "Admin")]
[HttpPost, Route("offline")]
public async Task<IActionResult> Offlineall()
{
_logger.LogInformation("Turning off all devices and sensors...");
await _service.OfflineallAsync();
await _hubContext.Clients.All.NotifyAllUpdatedAsync();
return Ok();
}
/// <summary>Bring all devices online</summary>
/// <returns>Message sent</returns>
[Authorize(Roles = "Admin")]
[HttpPost, Route("online")]
public async Task<IActionResult> Onlineall()
{
_logger.LogInformation("Turning on all devices and sensors...");
await _service.OnlineallAsync();
await _hubContext.Clients.All.NotifyAllUpdatedAsync();
return Ok();
}
/// <summary>Get all device info</summary>
/// <param name="deviceID">ID of device to query</param>
/// <returns>Information about a particular device</returns>
[HttpGet, Route("{deviceID}")]
public async Task<ActionResult<Device>> Getdevice([BindRequired] Guid deviceID)
{
_logger.LogInformation($"Getting device [{deviceID}]...");
return await _service.GetdeviceAsync(deviceID);
}
/// <summary>Shut down device</summary>
/// <param name="deviceID">ID of device to shut down</param>
/// <returns>Message sent</returns>
[Authorize(Roles = "Admin")]
[HttpPost, Route("{deviceID}/offline")]
public async Task<IActionResult> Offlinedevice([BindRequired] Guid deviceID)
{
_logger.LogInformation($"Turning off device [{deviceID}]...");
await _service.OfflinedeviceAsync(deviceID);
await _hubContext.Clients.All.NotifyDeviceUpdatedAsync(deviceID);
return Ok();
}
/// <summary>Bring device online</summary>
/// <param name="deviceID">ID of device to bring online</param>
/// <returns>Message sent</returns>
[Authorize(Roles = "Admin")]
[HttpPost, Route("{deviceID}/online")]
public async Task<IActionResult> Onlinedevice([BindRequired] Guid deviceID)
{
_logger.LogInformation($"Turning on device [{deviceID}]...");
await _service.OnlinedeviceAsync(deviceID);
await _hubContext.Clients.All.NotifyDeviceUpdatedAsync(deviceID);
return Ok();
}
/// <summary>Get info about a particular device's sensor</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Information about a sensor</returns>
[HttpGet, Route("{deviceID}/{sensorID}")]
public async Task<ActionResult<Sensor>> Getsensor([BindRequired] Guid deviceID, [BindRequired] Guid sensorID)
{
_logger.LogInformation($"Getting sensor [{sensorID}] of device [{deviceID}]...");
return await _service.GetsensorAsync(deviceID, sensorID);
}
/// <summary>Shut down sensor</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Message sent</returns>
[Authorize(Roles = "Admin")]
[HttpPost, Route("{deviceID}/{sensorID}/offline")]
public async Task<IActionResult> Offlinesensor([BindRequired] Guid deviceID, [BindRequired] Guid sensorID)
{
_logger.LogInformation($"Turning off sensor [{sensorID}] of device [{deviceID}]...");
await _service.OfflinesensorAsync(deviceID, sensorID);
await _hubContext.Clients.All.NotifyDeviceUpdatedAsync(deviceID);
return Ok();
}
/// <summary>Bring sensor online</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Message sent</returns>
[Authorize(Roles = "Admin")]
[HttpPost, Route("{deviceID}/{sensorID}/online")]
public async Task<IActionResult> Onlinesensor([BindRequired] Guid deviceID, [BindRequired] Guid sensorID)
{
_logger.LogInformation($"Turning on sensor [{sensorID}] of device [{deviceID}]...");
await _service.OnlinesensorAsync(deviceID, sensorID);
await _hubContext.Clients.All.NotifyDeviceUpdatedAsync(deviceID);
return Ok();
}
}
}
#pragma warning restore 1591
#pragma warning restore 1573
#pragma warning restore 472
#pragma warning restore 114
#pragma warning restore 108

View File

@ -14,7 +14,7 @@ using System.Threading.Tasks;
namespace Birdmap.API.Controllers
{
[Authorize]
[Authorize(Roles = "User, Admin")]
[ApiController]
[Route("api/[controller]")]
public class ServicesController : ControllerBase
@ -30,8 +30,7 @@ namespace Birdmap.API.Controllers
_logger = logger;
}
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[HttpGet, ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<List<ServiceInfo>>> GetAsync()
{
_logger.LogInformation($"Getting all services from db...");
@ -59,8 +58,8 @@ namespace Birdmap.API.Controllers
return serviceInfos.ToList();
}
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[Authorize(Roles = "Admin")]
[HttpPost, ProducesResponseType(StatusCodes.Status201Created)]
public async Task<ActionResult<ServiceRequest>> PostAsync(ServiceRequest request)
{
_logger.LogInformation($"Creating service [{request.Name}]...");
@ -74,8 +73,8 @@ namespace Birdmap.API.Controllers
_mapper.Map<ServiceRequest>(created));
}
[HttpPut]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[Authorize(Roles = "Admin")]
[HttpPut, ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> PutAsync(ServiceRequest request)
{
_logger.LogInformation($"Updating service [{request.Name}]...");
@ -87,8 +86,8 @@ namespace Birdmap.API.Controllers
return NoContent();
}
[HttpDelete("{id}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[Authorize(Roles = "Admin")]
[HttpDelete("{id}"), ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> DeleteAsync(int id)
{
_logger.LogInformation($"Deleting service [{id}]...");

View File

@ -2,7 +2,7 @@
namespace Birdmap.Models
{
public class AuthenticateRequest
public record AuthenticateRequest
{
[Required(AllowEmptyStrings = false, ErrorMessage = "Username is required.")]
public string Username { get; set; }

View File

@ -3,7 +3,7 @@ using Newtonsoft.Json;
namespace Birdmap.API.DTOs
{
public class AuthenticateResponse
public record AuthenticateResponse
{
[JsonProperty("user_name")]
public string Username { get; set; }

View File

@ -2,7 +2,7 @@
namespace Birdmap.API.DTOs
{
public class RegisterRequest
public record RegisterRequest
{
[Required(AllowEmptyStrings = false, ErrorMessage = "Username is required.")]
public string Username { get; set; }

View File

@ -2,7 +2,7 @@
namespace Birdmap.API.DTOs
{
public class ServiceInfo
public record ServiceInfo
{
public ServiceRequest Service { get; set; }
public HttpStatusCode StatusCode { get; set; }

View File

@ -1,6 +1,6 @@
namespace Birdmap.API.DTOs
{
public class ServiceRequest
public record ServiceRequest
{
public int Id { get; set; }
public string Name { get; set; }

View File

@ -0,0 +1,33 @@
using Birdmap.API.Options;
using Birdmap.API.Services.Mqtt;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
namespace Birdmap.API.Extensions
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMqttClientServiceWithConfig(this IServiceCollection services, Action<AspCoreMqttClientOptions> configureOptions)
{
services.AddSingleton(serviceProvider =>
{
var optionBuilder = new AspCoreMqttClientOptions(serviceProvider);
configureOptions(optionBuilder);
return optionBuilder.Build();
});
services.AddSingleton<MqttClientService>();
services.AddSingleton<IHostedService>(serviceProvider =>
{
return serviceProvider.GetService<MqttClientService>();
});
services.AddSingleton(serviceProvider =>
{
var mqttClientService = serviceProvider.GetService<MqttClientService>();
var mqttClientServiceProvider = new MqttClientServiceProvider(mqttClientService);
return mqttClientServiceProvider;
});
return services;
}
}
}

View File

@ -0,0 +1,22 @@
using MQTTnet.Client.Options;
using System;
namespace Birdmap.API.Options
{
public class AspCoreMqttClientOptions : MqttClientOptionsBuilder
{
public IServiceProvider ServiceProvider { get; }
public AspCoreMqttClientOptions(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
}
public AspCoreMqttClientOptions WithTopic(string topic)
{
WithUserProperty("Topic", topic);
return this;
}
}
}

View File

@ -1,4 +1,3 @@
using Birdmap.API;
using Birdmap.DAL;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
@ -8,7 +7,7 @@ using NLog;
using NLog.Web;
using System;
namespace Birdmap
namespace Birdmap.API
{
public class Program
{

View File

@ -0,0 +1,46 @@
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
namespace Birdmap.API.Services.Hubs
{
public class DevicesHub : Hub<IDevicesHubClient>
{
private readonly ILogger<DevicesHub> _logger;
public DevicesHub(ILogger<DevicesHub> logger)
{
_logger = logger;
}
public override Task OnConnectedAsync()
{
_logger.LogInformation("Hub Client connected.");
return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception exception)
{
_logger.LogInformation("Hub Client disconnected.");
return base.OnDisconnectedAsync(exception);
}
public Task SendProbabilityAsync(Guid deviceId, DateTime date, double probability)
{
return Clients.All.NotifyDeviceAsync(deviceId, date, probability);
}
public Task SendDeviceUpdateAsync(Guid deviceId)
{
return Clients.All.NotifyDeviceUpdatedAsync(deviceId);
}
public Task SendAllUpdatedAsync()
{
return Clients.All.NotifyAllUpdatedAsync();
}
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Threading.Tasks;
namespace Birdmap.API.Services
{
public interface IDevicesHubClient
{
Task NotifyDeviceAsync(Guid deviceId, DateTime date, double probability);
Task NotifyDeviceUpdatedAsync(Guid deviceId);
Task NotifyAllUpdatedAsync();
}
}

View File

@ -0,0 +1,15 @@
using Microsoft.Extensions.Hosting;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Receiving;
namespace Birdmap.API.Services
{
public interface IMqttClientService : IHostedService,
IMqttClientConnectedHandler,
IMqttClientDisconnectedHandler,
IMqttApplicationMessageReceivedHandler
{
}
}

View File

@ -0,0 +1,141 @@
using Birdmap.API.Services.Hubs;
using Birdmap.BLL.Interfaces;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Birdmap.API.Services.Mqtt
{
public class MqttClientService : IMqttClientService
{
private readonly IMqttClient _mqttClient;
private readonly IMqttClientOptions _options;
private readonly ILogger<MqttClientService> _logger;
private readonly IInputService _inputService;
private readonly IHubContext<DevicesHub, IDevicesHubClient> _hubContext;
public MqttClientService(IMqttClientOptions options, ILogger<MqttClientService> logger, IInputService inputService, IHubContext<DevicesHub, IDevicesHubClient> hubContext)
{
_options = options;
_logger = logger;
_inputService = inputService;
_hubContext = hubContext;
_mqttClient = new MqttFactory().CreateMqttClient();
ConfigureMqttClient();
}
private void ConfigureMqttClient()
{
_mqttClient.ConnectedHandler = this;
_mqttClient.DisconnectedHandler = this;
_mqttClient.ApplicationMessageReceivedHandler = this;
}
private class Payload
{
[JsonProperty("tag")]
public Guid TagID { get; set; }
[JsonProperty("probability")]
public double Probability { get; set; }
}
public async Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs eventArgs)
{
var message = eventArgs.ApplicationMessage.ConvertPayloadToString();
_logger.LogInformation($"Recieved [{eventArgs.ClientId}] " +
$"Topic: {eventArgs.ApplicationMessage.Topic} | Payload: {message} | QoS: {eventArgs.ApplicationMessage.QualityOfServiceLevel} | Retain: {eventArgs.ApplicationMessage.Retain}");
try
{
var payload = JsonConvert.DeserializeObject<Payload>(message);
var inputResponse = await _inputService.GetInputAsync(payload.TagID);
await _hubContext.Clients.All.NotifyDeviceAsync(inputResponse.Message.Device_id, inputResponse.Message.Date.UtcDateTime, payload.Probability);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Could not handle application message.");
}
}
public async Task HandleConnectedAsync(MqttClientConnectedEventArgs eventArgs)
{
try
{
var topic = _options.UserProperties.SingleOrDefault(up => up.Name == "Topic")?.Value;
_logger.LogInformation($"Connected. Auth result: {eventArgs.AuthenticateResult}. Subscribing to topic: {topic}");
await _mqttClient.SubscribeAsync(topic);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Cannot subscribe...");
}
}
public async Task HandleDisconnectedAsync(MqttClientDisconnectedEventArgs eventArgs)
{
_logger.LogWarning(eventArgs.Exception, $"Disconnected. Reason {eventArgs.ReasonCode}. Auth result: {eventArgs.AuthenticateResult}. Reconnecting...");
await Task.Delay(TimeSpan.FromSeconds(5));
try
{
await _mqttClient.ConnectAsync(_options, CancellationToken.None);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Reconnect failed...");
}
}
public async Task StartAsync(CancellationToken cancellationToken)
{
try
{
await _mqttClient.ConnectAsync(_options);
if (!_mqttClient.IsConnected)
{
await _mqttClient.ReconnectAsync();
}
}
catch (Exception ex)
{
_logger.LogError(ex, $"Cannot connect...");
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
try
{
if (cancellationToken.IsCancellationRequested)
{
var disconnectOption = new MqttClientDisconnectOptions
{
ReasonCode = MqttClientDisconnectReason.NormalDisconnection,
ReasonString = "NormalDiconnection"
};
await _mqttClient.DisconnectAsync(disconnectOption, cancellationToken);
}
await _mqttClient.DisconnectAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, $"Cannot disconnect...");
}
}
}
}

View File

@ -0,0 +1,12 @@
namespace Birdmap.API.Services.Mqtt
{
public class MqttClientServiceProvider
{
public IMqttClientService MqttClientService { get; }
public MqttClientServiceProvider(IMqttClientService mqttClientService)
{
MqttClientService = mqttClientService;
}
}
}

View File

@ -1,6 +1,7 @@
using AutoMapper;
using Birdmap.API;
using Birdmap.API.Extensions;
using Birdmap.API.Middlewares;
using Birdmap.API.Services.Hubs;
using Birdmap.BLL;
using Birdmap.DAL;
using Microsoft.AspNetCore.Authentication.JwtBearer;
@ -11,9 +12,10 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using NSwag.Generation.Processors.Security;
using System.Text;
namespace Birdmap
namespace Birdmap.API
{
public class Startup
{
@ -40,6 +42,8 @@ namespace Birdmap
services.AddAutoMapper(typeof(Startup));
services.AddSignalR();
var key = Encoding.ASCII.GetBytes(Configuration["Secret"]);
services.AddAuthentication(opt =>
{
@ -48,7 +52,7 @@ namespace Birdmap
})
.AddJwtBearer(opt =>
{
// opt.RequireHttpsMetadata = false;
//opt.RequireHttpsMetadata = false;
opt.SaveToken = true;
opt.IncludeErrorDetails = true;
opt.TokenValidationParameters = new TokenValidationParameters
@ -60,11 +64,52 @@ namespace Birdmap
};
});
services.AddMqttClientServiceWithConfig(opt =>
{
var mqtt = Configuration.GetSection("Mqtt");
var mqttClient = mqtt.GetSection("ClientSettings");
var clientSettings = new
{
Id = mqttClient.GetValue<string>("Id"),
Username = mqttClient.GetValue<string>("Username"),
Password = mqttClient.GetValue<string>("Password"),
Topic = mqttClient.GetValue<string>("Topic"),
};
var mqttBrokerHost = mqtt.GetSection("BrokerHostSettings");
var brokerHostSettings = new
{
Host = mqttBrokerHost.GetValue<string>("Host"),
Port = mqttBrokerHost.GetValue<int>("Port"),
};
opt
.WithTopic(clientSettings.Topic)
.WithCredentials(clientSettings.Username, clientSettings.Password)
.WithClientId(clientSettings.Id)
.WithTcpServer(brokerHostSettings.Host, brokerHostSettings.Port);
});
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
services.AddSwaggerDocument(opt =>
{
opt.Title = "Birdmap";
opt.OperationProcessors.Add(new OperationSecurityScopeProcessor("Jwt Token"));
opt.AddSecurity("Jwt Token", new string[] { },
new NSwag.OpenApiSecurityScheme
{
Type = NSwag.OpenApiSecuritySchemeType.ApiKey,
Name = "Authorization",
In = NSwag.OpenApiSecurityApiKeyLocation.Header,
Description = "Bearer {token}",
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -74,24 +119,26 @@ namespace Birdmap
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseMiddleware<ExceptionHandlerMiddleware>();
}
app.UseOpenApi();
app.UseSwaggerUi3();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapHealthChecks("/health");
endpoints.MapControllers();
endpoints.MapHub<DevicesHub>("/hubs/devices");
});
app.UseSpa(spa =>

View File

@ -8,7 +8,8 @@
},
"AllowedHosts": "*",
"Secret": "7vj.3KW.hYE!}4u6",
"LocalDbConnectionString": "Data Source=DESKTOP-A6JQ6B5\\SQLEXPRESS;Initial Catalog=Birdmap;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
// "LocalDbConnectionString": "Data Source=DESKTOP-3600\\SQLEXPRESS;Initial Catalog=birdmap;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
"LocalDbConnectionString": "Data Source=DESKTOP-3600;Initial Catalog=birdmap;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
"Defaults": {
"Services": {
"Local Database": "https://localhost:44331/health",
@ -26,5 +27,19 @@
"Role": "User"
}
]
},
"UseDummyServices": true,
"Mqtt": {
"BrokerHostSettings": {
"Host": "localhost",
"Port": 1883
},
"ClientSettings": {
"Id": "ASP.NET Core client",
"Username": "username",
"Password": "password",
"Topic": "devices/output"
}
}
}

View File

@ -14,22 +14,34 @@
<!-- the targets to write to -->
<targets async="true">
<default-target-parameters xsi:type="File" keepFileOpen="false" maxArchiveFiles="10" archiveAboveSize="1048576"/>
<target xsi:type="File" name="allfile" fileName="${basedir}Log/birdmap-all-${shortdate}.log"
layout="${longdate} [${event-properties:item=EventId_Id}] ${uppercase:${level}} ${logger} - ${message} ${exception:format=tostring}" />
<target xsi:type="File" name="allFile" fileName="${basedir}Log/birdmap-all-${shortdate}.log"
layout="${longdate} [${threadname:whenEmpty=${threadid}}] ${uppercase:${level}} ${logger} - ${message} ${exception:format=tostring}" />
<target xsi:type="File" name="mqttFile" fileName="${basedir}Log/birdmap-mqtt-${shortdate}.log"
layout="${longdate} [${threadname:whenEmpty=${threadid}}] ${uppercase:${level}} ${logger} - ${message} ${exception:format=tostring}" />
<target xsi:type="File" name="hubsFile" fileName="${basedir}Log/birdmap-hubs-${shortdate}.log"
layout="${longdate} [${threadname:whenEmpty=${threadid}}] ${uppercase:${level}} ${logger} - ${message} ${exception:format=tostring}" />
<!-- another file log, only own logs. Uses some ASP.NET core renderers -->
<target xsi:type="File" name="ownFile" fileName="${basedir}Log/birdmap-own-${shortdate}.log"
layout="${longdate} [${event-properties:item=EventId_Id}] ${uppercase:${level}} ${callsite} - ${message} ${exception:format=tostring} (url: ${aspnet-request-url})(action: ${aspnet-mvc-action})" />
layout="${longdate} [${threadname:whenEmpty=${threadid}}] ${uppercase:${level}} ${callsite} - ${message} ${exception:format=tostring} (url: ${aspnet-request-url})(action: ${aspnet-mvc-action})" />
</targets>
<!-- rules to map from logger name to target +-->
<rules>
<!--All logs, including from Microsoft-->
<logger name="*" minlevel="Trace" writeTo="allfile" />
<logger name="*" minlevel="Trace" writeTo="allFile" />
<!--Skip non-critical Microsoft logs and so log only own logs-->
<!--Skip non-critical Mqtt logs-->
<logger name="*.*Mqtt*.*" minlevel="Trace" maxlevel="Warning" writeTo="mqttFile" final="true"/>
<!--Skip non-critical Hub logs-->
<logger name="*.*Hubs*.*" minlevel="Trace" maxlevel="Warning" writeTo="hubsFile" final="true"/>
<!--Skip non-critical Microsoft logs-->
<logger name="Microsoft.*" maxlevel="Info" final="true" />
<!-- BlackHole without writeTo -->
<logger name="*" minlevel="Trace" writeTo="ownFile" />
</rules>
</nlog>

View File

@ -1,9 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Birdmap.Common\Birdmap.Common.csproj" />
<ProjectReference Include="..\Birdmap.DAL\Birdmap.DAL.csproj" />

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Birdmap.BLL.Helpers
{
public static class IEnumerableExtensions
{
public static TSource RandomElementAt<TSource>(this IEnumerable<TSource> source, Random random = null)
{
random ??= new Random();
return source.ElementAt(random.Next(source.Count()));
}
}
}

View File

@ -0,0 +1,279 @@
namespace Birdmap.BLL.Interfaces
{
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")]
public partial class ListOfDevices : System.Collections.ObjectModel.Collection<Device>
{
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")]
public partial class Device
{
[Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
public System.Guid Id { get; set; }
[Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
public DeviceStatus Status { get; set; }
[Newtonsoft.Json.JsonProperty("url", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
public string Url { get; set; }
[Newtonsoft.Json.JsonProperty("coordinates", Required = Newtonsoft.Json.Required.AllowNull)]
[System.ComponentModel.DataAnnotations.Required]
public Coordinates Coordinates { get; set; } = new Coordinates();
[Newtonsoft.Json.JsonProperty("sensors", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required]
public ArrayofSensors Sensors { get; set; } = new ArrayofSensors();
private System.Collections.Generic.IDictionary<string, object> _additionalProperties = new System.Collections.Generic.Dictionary<string, object>();
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties; }
set { _additionalProperties = value; }
}
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")]
public partial class ArrayofSensors : System.Collections.ObjectModel.Collection<Sensor>
{
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")]
public partial class Sensor
{
[Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
public System.Guid Id { get; set; }
[Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
public SensorStatus Status { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties = new System.Collections.Generic.Dictionary<string, object>();
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties; }
set { _additionalProperties = value; }
}
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")]
public partial class Coordinates
{
[Newtonsoft.Json.JsonProperty("latitude", Required = Newtonsoft.Json.Required.Always)]
public double Latitude { get; set; }
[Newtonsoft.Json.JsonProperty("longitude", Required = Newtonsoft.Json.Required.Always)]
public double Longitude { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties = new System.Collections.Generic.Dictionary<string, object>();
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties; }
set { _additionalProperties = value; }
}
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")]
public enum DeviceStatus
{
[System.Runtime.Serialization.EnumMember(Value = @"online")]
Online = 0,
[System.Runtime.Serialization.EnumMember(Value = @"error")]
Error = 1,
[System.Runtime.Serialization.EnumMember(Value = @"offline")]
Offline = 2,
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")]
public enum SensorStatus
{
[System.Runtime.Serialization.EnumMember(Value = @"online")]
Online = 0,
[System.Runtime.Serialization.EnumMember(Value = @"unknown")]
Unknown = 1,
[System.Runtime.Serialization.EnumMember(Value = @"offline")]
Offline = 2,
}
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0))")]
public partial class ApiException : System.Exception
{
public int StatusCode { get; private set; }
public string Response { get; private set; }
public System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> Headers { get; private set; }
public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers, System.Exception innerException)
: base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException)
{
StatusCode = statusCode;
Response = response;
Headers = headers;
}
public override string ToString()
{
return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString());
}
}
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0))")]
public partial class ApiException<TResult> : ApiException
{
public TResult Result { get; private set; }
public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers, TResult result, System.Exception innerException)
: base(message, statusCode, response, headers, innerException)
{
Result = result;
}
}
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0))")]
public partial interface IDeviceService
{
/// <summary>Get all device info</summary>
/// <returns>Array of devices</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<System.Collections.Generic.ICollection<Device>> GetallAsync();
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Get all device info</summary>
/// <returns>Array of devices</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<System.Collections.Generic.ICollection<Device>> GetallAsync(System.Threading.CancellationToken cancellationToken);
/// <summary>Shut down all devices</summary>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task OfflineallAsync();
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Shut down all devices</summary>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task OfflineallAsync(System.Threading.CancellationToken cancellationToken);
/// <summary>Bring all devices online</summary>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task OnlineallAsync();
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Bring all devices online</summary>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task OnlineallAsync(System.Threading.CancellationToken cancellationToken);
/// <summary>Get all device info</summary>
/// <param name="deviceID">ID of device to query</param>
/// <returns>Information about a particular device</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<Device> GetdeviceAsync(System.Guid deviceID);
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Get all device info</summary>
/// <param name="deviceID">ID of device to query</param>
/// <returns>Information about a particular device</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<Device> GetdeviceAsync(System.Guid deviceID, System.Threading.CancellationToken cancellationToken);
/// <summary>Shut down device</summary>
/// <param name="deviceID">ID of device to shut down</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task OfflinedeviceAsync(System.Guid deviceID);
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Shut down device</summary>
/// <param name="deviceID">ID of device to shut down</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task OfflinedeviceAsync(System.Guid deviceID, System.Threading.CancellationToken cancellationToken);
/// <summary>Bring device online</summary>
/// <param name="deviceID">ID of device to bring online</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task OnlinedeviceAsync(System.Guid deviceID);
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Bring device online</summary>
/// <param name="deviceID">ID of device to bring online</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task OnlinedeviceAsync(System.Guid deviceID, System.Threading.CancellationToken cancellationToken);
/// <summary>Get info about a particular device's sensor</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Information about a sensor</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<Sensor> GetsensorAsync(System.Guid deviceID, System.Guid sensorID);
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Get info about a particular device's sensor</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Information about a sensor</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<Sensor> GetsensorAsync(System.Guid deviceID, System.Guid sensorID, System.Threading.CancellationToken cancellationToken);
/// <summary>Shut down sensor</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task OfflinesensorAsync(System.Guid deviceID, System.Guid sensorID);
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Shut down sensor</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task OfflinesensorAsync(System.Guid deviceID, System.Guid sensorID, System.Threading.CancellationToken cancellationToken);
/// <summary>Bring sensor online</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task OnlinesensorAsync(System.Guid deviceID, System.Guid sensorID);
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Bring sensor online</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task OnlinesensorAsync(System.Guid deviceID, System.Guid sensorID, System.Threading.CancellationToken cancellationToken);
}
}

View File

@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Birdmap.BLL.Interfaces
{
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0))")]
public partial interface IInputService
{
/// <summary>Get input object by ID</summary>
/// <param name="tagID">ID of input object file</param>
/// <returns>input object</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<InputSingeResponse> GetInputAsync(System.Guid tagID);
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Get input object by ID</summary>
/// <param name="tagID">ID of input object file</param>
/// <returns>input object</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<InputSingeResponse> GetInputAsync(System.Guid tagID, System.Threading.CancellationToken cancellationToken);
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")]
public partial class InputSingeResponse
{
[Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
public string Status { get; set; }
[Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required]
public InputObject Message { get; set; } = new InputObject();
private System.Collections.Generic.IDictionary<string, object> _additionalProperties = new System.Collections.Generic.Dictionary<string, object>();
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties; }
set { _additionalProperties = value; }
}
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")]
public partial class InputResponse : System.Collections.ObjectModel.Collection<InputObject>
{
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")]
public partial class InputObject
{
[Newtonsoft.Json.JsonProperty("tag", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
public System.Guid Tag { get; set; }
[Newtonsoft.Json.JsonProperty("date", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
[Newtonsoft.Json.JsonConverter(typeof(DateFormatConverter))]
public System.DateTimeOffset Date { get; set; }
[Newtonsoft.Json.JsonProperty("device_id", Required = Newtonsoft.Json.Required.Always)]
public Guid Device_id { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties = new System.Collections.Generic.Dictionary<string, object>();
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties; }
set { _additionalProperties = value; }
}
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")]
public partial class ApiResponse
{
[Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
public string Status { get; set; }
[Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
public string Message { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties = new System.Collections.Generic.Dictionary<string, object>();
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties; }
set { _additionalProperties = value; }
}
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")]
public partial class Description
{
[Newtonsoft.Json.JsonProperty("deviceid", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Deviceid { get; set; }
[Newtonsoft.Json.JsonProperty("date", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
[Newtonsoft.Json.JsonConverter(typeof(DateFormatConverter))]
public System.DateTimeOffset Date { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties = new System.Collections.Generic.Dictionary<string, object>();
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties; }
set { _additionalProperties = value; }
}
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")]
internal class DateFormatConverter : Newtonsoft.Json.Converters.IsoDateTimeConverter
{
public DateFormatConverter()
{
DateTimeFormat = "yyyy-MM-dd";
}
}
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0))")]
public partial class FileParameter
{
public FileParameter(System.IO.Stream data)
: this(data, null, null)
{
}
public FileParameter(System.IO.Stream data, string fileName)
: this(data, fileName, null)
{
}
public FileParameter(System.IO.Stream data, string fileName, string contentType)
{
Data = data;
FileName = fileName;
ContentType = contentType;
}
public System.IO.Stream Data { get; private set; }
public string FileName { get; private set; }
public string ContentType { get; private set; }
}
}

View File

@ -0,0 +1,43 @@
using Birdmap.BLL.Interfaces;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Birdmap.BLL.Services
{
public abstract class DeviceAndInputServiceBase : IDeviceService, IInputService
{
public virtual Task<InputSingeResponse> GetInputAsync(Guid tagID)
=> GetInputAsync(tagID, CancellationToken.None);
public abstract Task<InputSingeResponse> GetInputAsync(Guid tagID, CancellationToken cancellationToken);
public virtual Task<ICollection<Device>> GetallAsync()
=> GetallAsync(CancellationToken.None);
public abstract Task<ICollection<Device>> GetallAsync(CancellationToken cancellationToken);
public virtual Task<Device> GetdeviceAsync(Guid deviceID)
=> GetdeviceAsync(deviceID, CancellationToken.None);
public abstract Task<Device> GetdeviceAsync(Guid deviceID, CancellationToken cancellationToken);
public virtual Task<Sensor> GetsensorAsync(Guid deviceID, Guid sensorID)
=> GetsensorAsync(deviceID, sensorID, CancellationToken.None);
public abstract Task<Sensor> GetsensorAsync(Guid deviceID, Guid sensorID, CancellationToken cancellationToken);
public virtual Task OfflineallAsync()
=> OfflineallAsync(CancellationToken.None);
public abstract Task OfflineallAsync(CancellationToken cancellationToken);
public virtual Task OfflinedeviceAsync(Guid deviceID)
=> OfflinedeviceAsync(deviceID, CancellationToken.None);
public abstract Task OfflinedeviceAsync(Guid deviceID, CancellationToken cancellationToken);
public virtual Task OfflinesensorAsync(Guid deviceID, Guid sensorID)
=> OfflinesensorAsync(deviceID, sensorID, CancellationToken.None);
public abstract Task OfflinesensorAsync(Guid deviceID, Guid sensorID, CancellationToken cancellationToken);
public virtual Task OnlineallAsync()
=> OnlineallAsync(CancellationToken.None);
public abstract Task OnlineallAsync(CancellationToken cancellationToken);
public virtual Task OnlinedeviceAsync(Guid deviceID)
=> OnlinedeviceAsync(deviceID, CancellationToken.None);
public abstract Task OnlinedeviceAsync(Guid deviceID, CancellationToken cancellationToken);
public virtual Task OnlinesensorAsync(Guid deviceID, Guid sensorID)
=> OnlinesensorAsync(deviceID, sensorID, CancellationToken.None);
public abstract Task OnlinesensorAsync(Guid deviceID, Guid sensorID, CancellationToken cancellationToken);
}
}

View File

@ -0,0 +1,171 @@
using Birdmap.BLL.Helpers;
using Birdmap.BLL.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Birdmap.BLL.Services
{
public class DummyDeviceAndInputService : DeviceAndInputServiceBase
{
private const int numberOfDevices = 15;
private const double centerLong = 21.469640;
private const double centerLat = 48.275939;
private const double radius = 0.001;
private static readonly Random Rand = new Random();
private static readonly Lazy<ICollection<Device>> Devices = new Lazy<ICollection<Device>>(GenerateDevices);
private static readonly Dictionary<Guid, InputSingeResponse> TagToInput = new Dictionary<Guid, InputSingeResponse>();
private static readonly object InputLock = new object();
private static ListOfDevices GenerateDevices()
{
var devices = new ListOfDevices();
T GetRandomEnum<T>()
{
var values = Enum.GetValues(typeof(T));
return (T)values.GetValue(Rand.Next(values.Length));
}
double GetPlusMinus(double center, double radius)
{
return center - radius + Rand.NextDouble() * radius * 2;
}
for (int d = 0; d < numberOfDevices; d++)
{
var sensors = new ArrayofSensors();
for (int s = 0; s < Rand.Next(1, 6); s++)
{
sensors.Add(new Sensor
{
Id = Guid.NewGuid(),
Status = GetRandomEnum<SensorStatus>(),
});
}
devices.Add(new Device
{
Id = Guid.NewGuid(),
Sensors = sensors,
Status = GetRandomEnum<DeviceStatus>(),
Url = "dummyservice.device.url",
Coordinates = new Coordinates
{
Latitude = GetPlusMinus(centerLat, radius),
Longitude = GetPlusMinus(centerLong, radius),
}
});
}
return devices;
}
public override Task<ICollection<Device>> GetallAsync(CancellationToken cancellationToken)
{
return Task.FromResult(Devices.Value);
}
public override Task<Device> GetdeviceAsync(Guid deviceID, CancellationToken cancellationToken)
{
return Task.FromResult(Devices.Value.SingleOrDefault(d => d.Id == deviceID));
}
public override Task<Sensor> GetsensorAsync(Guid deviceID, Guid sensorID, CancellationToken cancellationToken)
{
return Task.FromResult(Devices.Value.SingleOrDefault(d => d.Id == deviceID)?.Sensors.SingleOrDefault(s => s.Id == sensorID));
}
public override Task OfflineallAsync(CancellationToken cancellationToken)
{
SetStatus(DeviceStatus.Offline, SensorStatus.Offline);
return Task.CompletedTask;
}
public override Task OfflinedeviceAsync(Guid deviceID, CancellationToken cancellationToken)
{
SetDeviceStatus(deviceID, DeviceStatus.Offline);
return Task.CompletedTask;
}
public override Task OfflinesensorAsync(Guid deviceID, Guid sensorID, CancellationToken cancellationToken)
{
SetSensorStatus(deviceID, sensorID, SensorStatus.Offline);
return Task.CompletedTask;
}
public override Task OnlineallAsync(CancellationToken cancellationToken)
{
SetStatus(DeviceStatus.Online, SensorStatus.Online);
return Task.CompletedTask;
}
public override Task OnlinedeviceAsync(Guid deviceID, CancellationToken cancellationToken)
{
SetDeviceStatus(deviceID, DeviceStatus.Online);
return Task.CompletedTask;
}
public override Task OnlinesensorAsync(Guid deviceID, Guid sensorID, CancellationToken cancellationToken)
{
SetSensorStatus(deviceID, sensorID, SensorStatus.Online);
return Task.CompletedTask;
}
private void SetStatus(DeviceStatus deviceStatus, SensorStatus sensorStatus)
{
foreach (var device in Devices.Value)
{
device.Status = deviceStatus;
foreach (var sensor in device.Sensors)
{
sensor.Status = sensorStatus;
}
}
}
private void SetDeviceStatus(Guid deviceID, DeviceStatus status)
{
var device = GetdeviceAsync(deviceID).Result;
device.Status = status;
}
private void SetSensorStatus(Guid deviceId, Guid sensorID, SensorStatus status)
{
var sensor = GetsensorAsync(deviceId, sensorID).Result;
sensor.Status = status;
}
public override Task<InputSingeResponse> GetInputAsync(Guid tagID, CancellationToken cancellationToken)
{
lock (InputLock)
{
if (!TagToInput.TryGetValue(tagID, out var value))
{
value = new InputSingeResponse
{
Status = "Dummy_OK",
Message = new InputObject
{
Tag = tagID,
Date = DateTime.Now,
Device_id = Devices.Value.Where(d => d.Status == DeviceStatus.Online).RandomElementAt(Rand).Id,
}
};
TagToInput.TryAdd(tagID, value);
}
return Task.FromResult(value);
}
}
}
}

View File

@ -0,0 +1,904 @@
//----------------------
// <auto-generated>
// Generated using the NSwag toolchain v13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------
#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended."
#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword."
#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?'
#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ...
#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..."
#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type '...' is never equal to 'null' of type '...?'"
namespace Birdmap.BLL.Services
{
using Birdmap.BLL.Interfaces;
using System = global::System;
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0))")]
public partial class LiveDummyService : IDeviceService
{
private string _baseUrl = "https://birb.k8s.kmlabz.com";
private System.Net.Http.HttpClient _httpClient;
private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;
public LiveDummyService(System.Net.Http.HttpClient httpClient)
{
_httpClient = httpClient;
_settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings);
}
private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings()
{
var settings = new Newtonsoft.Json.JsonSerializerSettings();
UpdateJsonSerializerSettings(settings);
return settings;
}
public string BaseUrl
{
get { return _baseUrl; }
set { _baseUrl = value; }
}
protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } }
partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings);
partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url);
partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder);
partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response);
/// <summary>Get all device info</summary>
/// <returns>Array of devices</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public System.Threading.Tasks.Task<System.Collections.Generic.ICollection<Device>> GetallAsync()
{
return GetallAsync(System.Threading.CancellationToken.None);
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Get all device info</summary>
/// <returns>Array of devices</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public async System.Threading.Tasks.Task<System.Collections.Generic.ICollection<Device>> GetallAsync(System.Threading.CancellationToken cancellationToken)
{
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices");
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json"));
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
var objectResponse_ = await ReadObjectResponseAsync<System.Collections.Generic.ICollection<Device>>(response_, headers_).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
if (status_ == 404)
{
string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("No device found", status_, responseText_, headers_, null);
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>Shut down all devices</summary>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public System.Threading.Tasks.Task OfflineallAsync()
{
return OfflineallAsync(System.Threading.CancellationToken.None);
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Shut down all devices</summary>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public async System.Threading.Tasks.Task OfflineallAsync(System.Threading.CancellationToken cancellationToken)
{
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/offline");
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json");
request_.Method = new System.Net.Http.HttpMethod("POST");
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
return;
}
else
if (status_ == 500)
{
string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("Message sending unsuccessful", status_, responseText_, headers_, null);
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>Bring all devices online</summary>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public System.Threading.Tasks.Task OnlineallAsync()
{
return OnlineallAsync(System.Threading.CancellationToken.None);
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Bring all devices online</summary>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public async System.Threading.Tasks.Task OnlineallAsync(System.Threading.CancellationToken cancellationToken)
{
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/online");
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json");
request_.Method = new System.Net.Http.HttpMethod("POST");
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
return;
}
else
if (status_ == 500)
{
string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("Message sending unsuccessful", status_, responseText_, headers_, null);
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>Get all device info</summary>
/// <param name="deviceID">ID of device to query</param>
/// <returns>Information about a particular device</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public System.Threading.Tasks.Task<Device> GetdeviceAsync(System.Guid deviceID)
{
return GetdeviceAsync(deviceID, System.Threading.CancellationToken.None);
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Get all device info</summary>
/// <param name="deviceID">ID of device to query</param>
/// <returns>Information about a particular device</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public async System.Threading.Tasks.Task<Device> GetdeviceAsync(System.Guid deviceID, System.Threading.CancellationToken cancellationToken)
{
if (deviceID == null)
throw new System.ArgumentNullException("deviceID");
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/{deviceID}");
urlBuilder_.Replace("{deviceID}", System.Uri.EscapeDataString(ConvertToString(deviceID, System.Globalization.CultureInfo.InvariantCulture)));
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json"));
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
var objectResponse_ = await ReadObjectResponseAsync<Device>(response_, headers_).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
if (status_ == 404)
{
string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("Device not found", status_, responseText_, headers_, null);
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>Shut down device</summary>
/// <param name="deviceID">ID of device to shut down</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public System.Threading.Tasks.Task OfflinedeviceAsync(System.Guid deviceID)
{
return OfflinedeviceAsync(deviceID, System.Threading.CancellationToken.None);
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Shut down device</summary>
/// <param name="deviceID">ID of device to shut down</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public async System.Threading.Tasks.Task OfflinedeviceAsync(System.Guid deviceID, System.Threading.CancellationToken cancellationToken)
{
if (deviceID == null)
throw new System.ArgumentNullException("deviceID");
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/{deviceID}/offline");
urlBuilder_.Replace("{deviceID}", System.Uri.EscapeDataString(ConvertToString(deviceID, System.Globalization.CultureInfo.InvariantCulture)));
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json");
request_.Method = new System.Net.Http.HttpMethod("POST");
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
return;
}
else
if (status_ == 500)
{
string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("Message sending unsuccessful", status_, responseText_, headers_, null);
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>Bring device online</summary>
/// <param name="deviceID">ID of device to bring online</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public System.Threading.Tasks.Task OnlinedeviceAsync(System.Guid deviceID)
{
return OnlinedeviceAsync(deviceID, System.Threading.CancellationToken.None);
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Bring device online</summary>
/// <param name="deviceID">ID of device to bring online</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public async System.Threading.Tasks.Task OnlinedeviceAsync(System.Guid deviceID, System.Threading.CancellationToken cancellationToken)
{
if (deviceID == null)
throw new System.ArgumentNullException("deviceID");
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/{deviceID}/online");
urlBuilder_.Replace("{deviceID}", System.Uri.EscapeDataString(ConvertToString(deviceID, System.Globalization.CultureInfo.InvariantCulture)));
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json");
request_.Method = new System.Net.Http.HttpMethod("POST");
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
return;
}
else
if (status_ == 500)
{
string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("Message sending unsuccessful", status_, responseText_, headers_, null);
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>Get info about a particular device's sensor</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Information about a sensor</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public System.Threading.Tasks.Task<Sensor> GetsensorAsync(System.Guid deviceID, System.Guid sensorID)
{
return GetsensorAsync(deviceID, sensorID, System.Threading.CancellationToken.None);
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Get info about a particular device's sensor</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Information about a sensor</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public async System.Threading.Tasks.Task<Sensor> GetsensorAsync(System.Guid deviceID, System.Guid sensorID, System.Threading.CancellationToken cancellationToken)
{
if (deviceID == null)
throw new System.ArgumentNullException("deviceID");
if (sensorID == null)
throw new System.ArgumentNullException("sensorID");
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/{deviceID}/{sensorID}");
urlBuilder_.Replace("{deviceID}", System.Uri.EscapeDataString(ConvertToString(deviceID, System.Globalization.CultureInfo.InvariantCulture)));
urlBuilder_.Replace("{sensorID}", System.Uri.EscapeDataString(ConvertToString(sensorID, System.Globalization.CultureInfo.InvariantCulture)));
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json"));
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
var objectResponse_ = await ReadObjectResponseAsync<Sensor>(response_, headers_).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
if (status_ == 404)
{
string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("Device or sensor not found", status_, responseText_, headers_, null);
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>Shut down sensor</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public System.Threading.Tasks.Task OfflinesensorAsync(System.Guid deviceID, System.Guid sensorID)
{
return OfflinesensorAsync(deviceID, sensorID, System.Threading.CancellationToken.None);
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Shut down sensor</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public async System.Threading.Tasks.Task OfflinesensorAsync(System.Guid deviceID, System.Guid sensorID, System.Threading.CancellationToken cancellationToken)
{
if (deviceID == null)
throw new System.ArgumentNullException("deviceID");
if (sensorID == null)
throw new System.ArgumentNullException("sensorID");
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/{deviceID}/{sensorID}/offline");
urlBuilder_.Replace("{deviceID}", System.Uri.EscapeDataString(ConvertToString(deviceID, System.Globalization.CultureInfo.InvariantCulture)));
urlBuilder_.Replace("{sensorID}", System.Uri.EscapeDataString(ConvertToString(sensorID, System.Globalization.CultureInfo.InvariantCulture)));
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json");
request_.Method = new System.Net.Http.HttpMethod("POST");
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
return;
}
else
if (status_ == 500)
{
string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("Message sending unsuccessful", status_, responseText_, headers_, null);
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>Bring sensor online</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public System.Threading.Tasks.Task OnlinesensorAsync(System.Guid deviceID, System.Guid sensorID)
{
return OnlinesensorAsync(deviceID, sensorID, System.Threading.CancellationToken.None);
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Bring sensor online</summary>
/// <param name="deviceID">ID of device to query</param>
/// <param name="sensorID">ID of sensor to query</param>
/// <returns>Message sent</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public async System.Threading.Tasks.Task OnlinesensorAsync(System.Guid deviceID, System.Guid sensorID, System.Threading.CancellationToken cancellationToken)
{
if (deviceID == null)
throw new System.ArgumentNullException("deviceID");
if (sensorID == null)
throw new System.ArgumentNullException("sensorID");
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/{deviceID}/{sensorID}/online");
urlBuilder_.Replace("{deviceID}", System.Uri.EscapeDataString(ConvertToString(deviceID, System.Globalization.CultureInfo.InvariantCulture)));
urlBuilder_.Replace("{sensorID}", System.Uri.EscapeDataString(ConvertToString(sensorID, System.Globalization.CultureInfo.InvariantCulture)));
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json");
request_.Method = new System.Net.Http.HttpMethod("POST");
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
return;
}
else
if (status_ == 500)
{
string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("Message sending unsuccessful", status_, responseText_, headers_, null);
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
protected struct ObjectResponseResult<T>
{
public ObjectResponseResult(T responseObject, string responseText)
{
this.Object = responseObject;
this.Text = responseText;
}
public T Object { get; }
public string Text { get; }
}
public bool ReadResponseAsString { get; set; }
protected virtual async System.Threading.Tasks.Task<ObjectResponseResult<T>> ReadObjectResponseAsync<T>(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers)
{
if (response == null || response.Content == null)
{
return new ObjectResponseResult<T>(default(T), string.Empty);
}
if (ReadResponseAsString)
{
var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
try
{
var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseText, JsonSerializerSettings);
return new ObjectResponseResult<T>(typedBody, responseText);
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body string as " + typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception);
}
}
else
{
try
{
using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
using (var streamReader = new System.IO.StreamReader(responseStream))
using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader))
{
var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings);
var typedBody = serializer.Deserialize<T>(jsonTextReader);
return new ObjectResponseResult<T>(typedBody, string.Empty);
}
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body stream as " + typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception);
}
}
}
private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo)
{
if (value == null)
{
return null;
}
if (value is System.Enum)
{
var name = System.Enum.GetName(value.GetType(), value);
if (name != null)
{
var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name);
if (field != null)
{
var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute))
as System.Runtime.Serialization.EnumMemberAttribute;
if (attribute != null)
{
return attribute.Value != null ? attribute.Value : name;
}
}
return System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo));
}
}
else if (value is bool)
{
return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant();
}
else if (value is byte[])
{
return System.Convert.ToBase64String((byte[])value);
}
else if (value.GetType().IsArray)
{
var array = System.Linq.Enumerable.OfType<object>((System.Array)value);
return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo)));
}
var result = System.Convert.ToString(value, cultureInfo);
return (result is null) ? string.Empty : result;
}
}
}
#pragma warning restore 8703
#pragma warning restore 1591
#pragma warning restore 1573
#pragma warning restore 472
#pragma warning restore 114
#pragma warning restore 108

View File

@ -0,0 +1,479 @@
//----------------------
// <auto-generated>
// Generated using the NSwag toolchain v13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------
#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended."
#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword."
#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?'
#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ...
#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..."
#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type '...' is never equal to 'null' of type '...?'"
namespace Birdmap.BLL.Services
{
using Birdmap.BLL.Interfaces;
using System = global::System;
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0))")]
public partial class LiveInputService : IInputService
{
private string _baseUrl = "https://birb.k8s.kmlabz.com";
private System.Net.Http.HttpClient _httpClient;
private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;
public LiveInputService(System.Net.Http.HttpClient httpClient)
{
_httpClient = httpClient;
_settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings);
}
private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings()
{
var settings = new Newtonsoft.Json.JsonSerializerSettings();
UpdateJsonSerializerSettings(settings);
return settings;
}
public string BaseUrl
{
get { return _baseUrl; }
set { _baseUrl = value; }
}
protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } }
partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings);
partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url);
partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder);
partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response);
/// <summary>Get all stored input queries</summary>
/// <returns>Array of input objects</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public System.Threading.Tasks.Task<System.Collections.Generic.ICollection<InputObject>> GetallAsync()
{
return GetallAsync(System.Threading.CancellationToken.None);
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Get all stored input queries</summary>
/// <returns>Array of input objects</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public async System.Threading.Tasks.Task<System.Collections.Generic.ICollection<InputObject>> GetallAsync(System.Threading.CancellationToken cancellationToken)
{
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/sample");
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json"));
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
var objectResponse_ = await ReadObjectResponseAsync<System.Collections.Generic.ICollection<InputObject>>(response_, headers_).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
if (status_ == 404)
{
var objectResponse_ = await ReadObjectResponseAsync<ApiResponse>(response_, headers_).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
throw new ApiException<ApiResponse>("No object matching filter", status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>uploads a sample into the system</summary>
/// <returns>successful operation</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public System.Threading.Tasks.Task<ApiResponse> UploadFileAsync(Description description, FileParameter file)
{
return UploadFileAsync(description, file, System.Threading.CancellationToken.None);
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>uploads a sample into the system</summary>
/// <returns>successful operation</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public async System.Threading.Tasks.Task<ApiResponse> UploadFileAsync(Description description, FileParameter file, System.Threading.CancellationToken cancellationToken)
{
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/sample");
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
var boundary_ = System.Guid.NewGuid().ToString();
var content_ = new System.Net.Http.MultipartFormDataContent(boundary_);
content_.Headers.Remove("Content-Type");
content_.Headers.TryAddWithoutValidation("Content-Type", "multipart/form-data; boundary=" + boundary_);
if (description == null)
throw new System.ArgumentNullException("description");
else
{
content_.Add(new System.Net.Http.StringContent(ConvertToString(description, System.Globalization.CultureInfo.InvariantCulture)), "description");
}
if (file == null)
throw new System.ArgumentNullException("file");
else
{
var content_file_ = new System.Net.Http.StreamContent(file.Data);
if (!string.IsNullOrEmpty(file.ContentType))
content_file_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse(file.ContentType);
content_.Add(content_file_, "file", file.FileName ?? "file");
}
request_.Content = content_;
request_.Method = new System.Net.Http.HttpMethod("POST");
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json"));
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
var objectResponse_ = await ReadObjectResponseAsync<ApiResponse>(response_, headers_).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
if (status_ == 400)
{
var objectResponse_ = await ReadObjectResponseAsync<ApiResponse>(response_, headers_).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
throw new ApiException<ApiResponse>("JSON parse error", status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
}
else
if (status_ == 415)
{
var objectResponse_ = await ReadObjectResponseAsync<ApiResponse>(response_, headers_).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
throw new ApiException<ApiResponse>("Media type error", status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
}
else
if (status_ == 417)
{
var objectResponse_ = await ReadObjectResponseAsync<ApiResponse>(response_, headers_).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
throw new ApiException<ApiResponse>("JSON invalid schema", status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
}
else
if (status_ == 469)
{
var objectResponse_ = await ReadObjectResponseAsync<ApiResponse>(response_, headers_).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
throw new ApiException<ApiResponse>("No file found", status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
}
else
if (status_ == 470)
{
var objectResponse_ = await ReadObjectResponseAsync<ApiResponse>(response_, headers_).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
throw new ApiException<ApiResponse>("Description missing", status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
/// <summary>Get input object by ID</summary>
/// <param name="tagID">ID of input object file</param>
/// <returns>input object</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public System.Threading.Tasks.Task<InputSingeResponse> GetInputAsync(System.Guid tagID)
{
return GetInputAsync(tagID, System.Threading.CancellationToken.None);
}
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <summary>Get input object by ID</summary>
/// <param name="tagID">ID of input object file</param>
/// <returns>input object</returns>
/// <exception cref="ApiException">A server side error occurred.</exception>
public async System.Threading.Tasks.Task<InputSingeResponse> GetInputAsync(System.Guid tagID, System.Threading.CancellationToken cancellationToken)
{
if (tagID == null)
throw new System.ArgumentNullException("tagID");
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/sample/{tagID}");
urlBuilder_.Replace("{tagID}", System.Uri.EscapeDataString(ConvertToString(tagID, System.Globalization.CultureInfo.InvariantCulture)));
var client_ = _httpClient;
var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json"));
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = (int)response_.StatusCode;
if (status_ == 200)
{
var objectResponse_ = await ReadObjectResponseAsync<InputSingeResponse>(response_, headers_).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
if (status_ == 404)
{
var objectResponse_ = await ReadObjectResponseAsync<ApiResponse>(response_, headers_).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
}
throw new ApiException<ApiResponse>("Tag not found", status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
}
else
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
protected struct ObjectResponseResult<T>
{
public ObjectResponseResult(T responseObject, string responseText)
{
this.Object = responseObject;
this.Text = responseText;
}
public T Object { get; }
public string Text { get; }
}
public bool ReadResponseAsString { get; set; }
protected virtual async System.Threading.Tasks.Task<ObjectResponseResult<T>> ReadObjectResponseAsync<T>(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers)
{
if (response == null || response.Content == null)
{
return new ObjectResponseResult<T>(default(T), string.Empty);
}
if (ReadResponseAsString)
{
var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
try
{
var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseText, JsonSerializerSettings);
return new ObjectResponseResult<T>(typedBody, responseText);
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body string as " + typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception);
}
}
else
{
try
{
using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
using (var streamReader = new System.IO.StreamReader(responseStream))
using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader))
{
var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings);
var typedBody = serializer.Deserialize<T>(jsonTextReader);
return new ObjectResponseResult<T>(typedBody, string.Empty);
}
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body stream as " + typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception);
}
}
}
private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo)
{
if (value == null)
{
return null;
}
if (value is System.Enum)
{
var name = System.Enum.GetName(value.GetType(), value);
if (name != null)
{
var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name);
if (field != null)
{
var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute))
as System.Runtime.Serialization.EnumMemberAttribute;
if (attribute != null)
{
return attribute.Value != null ? attribute.Value : name;
}
}
return System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo));
}
}
else if (value is bool)
{
return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant();
}
else if (value is byte[])
{
return System.Convert.ToBase64String((byte[])value);
}
else if (value.GetType().IsArray)
{
var array = System.Linq.Enumerable.OfType<object>((System.Array)value);
return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo)));
}
var result = System.Convert.ToString(value, cultureInfo);
return (result is null) ? string.Empty : result;
}
}
}
#pragma warning restore 8703
#pragma warning restore 1591
#pragma warning restore 1573
#pragma warning restore 472
#pragma warning restore 114
#pragma warning restore 108

View File

@ -13,6 +13,17 @@ namespace Birdmap.BLL
services.AddTransient<IUserService, UserService>();
services.AddTransient<IServiceService, ServiceService>();
if (configuration.GetValue<bool>("UseDummyServices"))
{
services.AddTransient<IInputService, DummyDeviceAndInputService>();
services.AddTransient<IDeviceService, DummyDeviceAndInputService>();
}
else
{
services.AddTransient<IInputService, LiveInputService>();
services.AddTransient<IDeviceService, LiveDummyService>();
}
return services;
}
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
</Project>

View File

@ -1,17 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.9">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="3.1.9" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="5.0.0" />
</ItemGroup>
<ItemGroup>

View File

@ -2,7 +2,7 @@
namespace Birdmap.DAL.Entities
{
public class Service
public record Service
{
public int Id { get; set; }
public string Name { get; set; }

View File

@ -6,7 +6,7 @@
Admin,
}
public class User
public record User
{
public int Id { get; set; }
public string Name { get; set; }

View File

@ -9,7 +9,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Birdmap.BLL", "Birdmap.BLL\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Birdmap.DAL", "Birdmap.DAL\Birdmap.DAL.csproj", "{543FAB06-B960-41A9-8865-1624A2ED2170}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Birdmap.Common", "Birdmap.Common\Birdmap.Common.csproj", "{CE96BAFA-A0FD-4010-8EF2-700451091F71}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Birdmap.Common", "Birdmap.Common\Birdmap.Common.csproj", "{CE96BAFA-A0FD-4010-8EF2-700451091F71}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.TestApp.WinForm", "MQTTnet.TestApp.WinForm\MQTTnet.TestApp.WinForm.csproj", "{E1707FE7-4A65-42AC-B71C-6CC1A55FC42A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -33,6 +35,10 @@ Global
{CE96BAFA-A0FD-4010-8EF2-700451091F71}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CE96BAFA-A0FD-4010-8EF2-700451091F71}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CE96BAFA-A0FD-4010-8EF2-700451091F71}.Release|Any CPU.Build.0 = Release|Any CPU
{E1707FE7-4A65-42AC-B71C-6CC1A55FC42A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1707FE7-4A65-42AC-B71C-6CC1A55FC42A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1707FE7-4A65-42AC-B71C-6CC1A55FC42A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1707FE7-4A65-42AC-B71C-6CC1A55FC42A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

394
MQTTnet.TestApp.WinForm/Form1.Designer.cs generated Normal file
View File

@ -0,0 +1,394 @@
namespace MQTTnet.TestApp.WinForm
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.TextBoxPort = new System.Windows.Forms.TextBox();
this.ButtonServerStart = new System.Windows.Forms.Button();
this.ButtonServerStop = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.maskedTextBox1 = new System.Windows.Forms.MaskedTextBox();
this.label3 = new System.Windows.Forms.Label();
this.TextBoxTopicPublished = new System.Windows.Forms.TextBox();
this.label4 = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
this.ButtonPublisherStop = new System.Windows.Forms.Button();
this.ButtonPublisherStart = new System.Windows.Forms.Button();
this.TextBoxPublish = new System.Windows.Forms.TextBox();
this.ButtonPublish = new System.Windows.Forms.Button();
this.ButtonSubscriberStop = new System.Windows.Forms.Button();
this.ButtonSubscriberStart = new System.Windows.Forms.Button();
this.TextBoxSubscriber = new System.Windows.Forms.TextBox();
this.ButtonGeneratePublishedMessage = new System.Windows.Forms.Button();
this.label6 = new System.Windows.Forms.Label();
this.TextBoxTopicSubscribed = new System.Windows.Forms.TextBox();
this.ButtonSubscribe = new System.Windows.Forms.Button();
this.label7 = new System.Windows.Forms.Label();
this.trackBar1 = new System.Windows.Forms.TrackBar();
this.ButtonAutoPublisherStop = new System.Windows.Forms.Button();
this.ButtonAutoPublisherStart = new System.Windows.Forms.Button();
this.label8 = new System.Windows.Forms.Label();
this.checkBox1 = new System.Windows.Forms.CheckBox();
((System.ComponentModel.ISupportInitialize)(this.trackBar1)).BeginInit();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(119, 24);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(32, 15);
this.label1.TabIndex = 0;
this.label1.Text = "Port:";
//
// TextBoxPort
//
this.TextBoxPort.Location = new System.Drawing.Point(172, 21);
this.TextBoxPort.Name = "TextBoxPort";
this.TextBoxPort.Size = new System.Drawing.Size(100, 23);
this.TextBoxPort.TabIndex = 1;
this.TextBoxPort.Text = "1883";
this.TextBoxPort.TextChanged += new System.EventHandler(this.TextBoxPortTextChanged);
//
// ButtonServerStart
//
this.ButtonServerStart.Location = new System.Drawing.Point(433, 21);
this.ButtonServerStart.Name = "ButtonServerStart";
this.ButtonServerStart.Size = new System.Drawing.Size(75, 23);
this.ButtonServerStart.TabIndex = 2;
this.ButtonServerStart.Text = "Start";
this.ButtonServerStart.UseVisualStyleBackColor = true;
this.ButtonServerStart.Click += new System.EventHandler(this.ButtonServerStartClick);
//
// ButtonServerStop
//
this.ButtonServerStop.Location = new System.Drawing.Point(514, 21);
this.ButtonServerStop.Name = "ButtonServerStop";
this.ButtonServerStop.Size = new System.Drawing.Size(75, 23);
this.ButtonServerStop.TabIndex = 3;
this.ButtonServerStop.Text = "Stop";
this.ButtonServerStop.UseVisualStyleBackColor = true;
this.ButtonServerStop.Click += new System.EventHandler(this.ButtonServerStopClick);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(33, 25);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(39, 15);
this.label2.TabIndex = 4;
this.label2.Text = "Server";
//
// maskedTextBox1
//
this.maskedTextBox1.Location = new System.Drawing.Point(0, 0);
this.maskedTextBox1.Name = "maskedTextBox1";
this.maskedTextBox1.Size = new System.Drawing.Size(100, 23);
this.maskedTextBox1.TabIndex = 5;
this.maskedTextBox1.Text = "maskedTextBox1";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(33, 79);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(90, 15);
this.label3.TabIndex = 5;
this.label3.Text = "Topic Published";
//
// TextBoxTopicPublished
//
this.TextBoxTopicPublished.Location = new System.Drawing.Point(164, 76);
this.TextBoxTopicPublished.Name = "TextBoxTopicPublished";
this.TextBoxTopicPublished.Size = new System.Drawing.Size(425, 23);
this.TextBoxTopicPublished.TabIndex = 1;
this.TextBoxTopicPublished.Text = "devices/output";
this.TextBoxTopicPublished.TextChanged += new System.EventHandler(this.TextBoxPortTextChanged);
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(33, 109);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(90, 15);
this.label4.TabIndex = 5;
this.label4.Text = "Client Publisher";
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(33, 224);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(96, 15);
this.label5.TabIndex = 5;
this.label5.Text = "Client Subscriber";
//
// ButtonPublisherStop
//
this.ButtonPublisherStop.Location = new System.Drawing.Point(514, 105);
this.ButtonPublisherStop.Name = "ButtonPublisherStop";
this.ButtonPublisherStop.Size = new System.Drawing.Size(75, 23);
this.ButtonPublisherStop.TabIndex = 3;
this.ButtonPublisherStop.Text = "Stop";
this.ButtonPublisherStop.UseVisualStyleBackColor = true;
this.ButtonPublisherStop.Click += new System.EventHandler(this.ButtonPublisherStopClick);
//
// ButtonPublisherStart
//
this.ButtonPublisherStart.Location = new System.Drawing.Point(433, 105);
this.ButtonPublisherStart.Name = "ButtonPublisherStart";
this.ButtonPublisherStart.Size = new System.Drawing.Size(75, 23);
this.ButtonPublisherStart.TabIndex = 2;
this.ButtonPublisherStart.Text = "Start";
this.ButtonPublisherStart.UseVisualStyleBackColor = true;
this.ButtonPublisherStart.Click += new System.EventHandler(this.ButtonPublisherStartClick);
//
// TextBoxPublish
//
this.TextBoxPublish.Location = new System.Drawing.Point(33, 134);
this.TextBoxPublish.Name = "TextBoxPublish";
this.TextBoxPublish.Size = new System.Drawing.Size(394, 23);
this.TextBoxPublish.TabIndex = 1;
this.TextBoxPublish.TextChanged += new System.EventHandler(this.TextBoxPortTextChanged);
//
// ButtonPublish
//
this.ButtonPublish.Location = new System.Drawing.Point(514, 134);
this.ButtonPublish.Name = "ButtonPublish";
this.ButtonPublish.Size = new System.Drawing.Size(75, 23);
this.ButtonPublish.TabIndex = 3;
this.ButtonPublish.Text = "Publish";
this.ButtonPublish.UseVisualStyleBackColor = true;
this.ButtonPublish.Click += new System.EventHandler(this.ButtonPublishClick);
//
// ButtonSubscriberStop
//
this.ButtonSubscriberStop.Location = new System.Drawing.Point(514, 220);
this.ButtonSubscriberStop.Name = "ButtonSubscriberStop";
this.ButtonSubscriberStop.Size = new System.Drawing.Size(75, 23);
this.ButtonSubscriberStop.TabIndex = 3;
this.ButtonSubscriberStop.Text = "Stop";
this.ButtonSubscriberStop.UseVisualStyleBackColor = true;
this.ButtonSubscriberStop.Click += new System.EventHandler(this.ButtonSubscriberStopClick);
//
// ButtonSubscriberStart
//
this.ButtonSubscriberStart.Location = new System.Drawing.Point(433, 220);
this.ButtonSubscriberStart.Name = "ButtonSubscriberStart";
this.ButtonSubscriberStart.Size = new System.Drawing.Size(75, 23);
this.ButtonSubscriberStart.TabIndex = 2;
this.ButtonSubscriberStart.Text = "Start";
this.ButtonSubscriberStart.UseVisualStyleBackColor = true;
this.ButtonSubscriberStart.Click += new System.EventHandler(this.ButtonSubscriberStartClick);
//
// TextBoxSubscriber
//
this.TextBoxSubscriber.Location = new System.Drawing.Point(33, 309);
this.TextBoxSubscriber.Multiline = true;
this.TextBoxSubscriber.Name = "TextBoxSubscriber";
this.TextBoxSubscriber.Size = new System.Drawing.Size(556, 182);
this.TextBoxSubscriber.TabIndex = 6;
//
// ButtonGeneratePublishedMessage
//
this.ButtonGeneratePublishedMessage.Location = new System.Drawing.Point(433, 133);
this.ButtonGeneratePublishedMessage.Name = "ButtonGeneratePublishedMessage";
this.ButtonGeneratePublishedMessage.Size = new System.Drawing.Size(75, 23);
this.ButtonGeneratePublishedMessage.TabIndex = 2;
this.ButtonGeneratePublishedMessage.Text = "Random";
this.ButtonGeneratePublishedMessage.UseVisualStyleBackColor = true;
this.ButtonGeneratePublishedMessage.Click += new System.EventHandler(this.ButtonGeneratePublishedMessageClick);
//
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(33, 252);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(96, 15);
this.label6.TabIndex = 5;
this.label6.Text = "Topic Subscribed";
//
// TextBoxTopicSubscribed
//
this.TextBoxTopicSubscribed.Location = new System.Drawing.Point(164, 249);
this.TextBoxTopicSubscribed.Name = "TextBoxTopicSubscribed";
this.TextBoxTopicSubscribed.Size = new System.Drawing.Size(344, 23);
this.TextBoxTopicSubscribed.TabIndex = 1;
this.TextBoxTopicSubscribed.Text = "devices/output";
this.TextBoxTopicSubscribed.TextChanged += new System.EventHandler(this.TextBoxPortTextChanged);
//
// ButtonSubscribe
//
this.ButtonSubscribe.Location = new System.Drawing.Point(514, 248);
this.ButtonSubscribe.Name = "ButtonSubscribe";
this.ButtonSubscribe.Size = new System.Drawing.Size(75, 23);
this.ButtonSubscribe.TabIndex = 3;
this.ButtonSubscribe.Text = "Subscribe";
this.ButtonSubscribe.UseVisualStyleBackColor = true;
this.ButtonSubscribe.Click += new System.EventHandler(this.ButtonSubscribeClick);
//
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(33, 167);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(141, 15);
this.label7.TabIndex = 5;
this.label7.Text = "Auto (Random) Publisher";
//
// trackBar1
//
this.trackBar1.LargeChange = 500;
this.trackBar1.Location = new System.Drawing.Point(180, 162);
this.trackBar1.Maximum = 5050;
this.trackBar1.Minimum = 50;
this.trackBar1.Name = "trackBar1";
this.trackBar1.Size = new System.Drawing.Size(247, 45);
this.trackBar1.SmallChange = 100;
this.trackBar1.TabIndex = 7;
this.trackBar1.TickFrequency = 500;
this.trackBar1.Value = 550;
this.trackBar1.Scroll += new System.EventHandler(this.trackBar1_Scroll);
//
// ButtonAutoPublisherStop
//
this.ButtonAutoPublisherStop.Location = new System.Drawing.Point(513, 162);
this.ButtonAutoPublisherStop.Name = "ButtonAutoPublisherStop";
this.ButtonAutoPublisherStop.Size = new System.Drawing.Size(75, 23);
this.ButtonAutoPublisherStop.TabIndex = 8;
this.ButtonAutoPublisherStop.Text = "Stop";
this.ButtonAutoPublisherStop.UseVisualStyleBackColor = true;
this.ButtonAutoPublisherStop.Click += new System.EventHandler(this.ButtonAutoPublisherStopClick);
//
// ButtonAutoPublisherStart
//
this.ButtonAutoPublisherStart.Location = new System.Drawing.Point(433, 162);
this.ButtonAutoPublisherStart.Name = "ButtonAutoPublisherStart";
this.ButtonAutoPublisherStart.Size = new System.Drawing.Size(75, 23);
this.ButtonAutoPublisherStart.TabIndex = 8;
this.ButtonAutoPublisherStart.Text = "Start";
this.ButtonAutoPublisherStart.UseVisualStyleBackColor = true;
this.ButtonAutoPublisherStart.Click += new System.EventHandler(this.ButtonAutoPublisherStartClick);
//
// label8
//
this.label8.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.label8.AutoSize = true;
this.label8.Location = new System.Drawing.Point(180, 191);
this.label8.Name = "label8";
this.label8.RightToLeft = System.Windows.Forms.RightToLeft.No;
this.label8.Size = new System.Drawing.Size(44, 15);
this.label8.TabIndex = 9;
this.label8.Text = "550 ms";
this.label8.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// checkBox1
//
this.checkBox1.AutoSize = true;
this.checkBox1.Checked = true;
this.checkBox1.CheckState = System.Windows.Forms.CheckState.Checked;
this.checkBox1.Location = new System.Drawing.Point(433, 191);
this.checkBox1.Name = "checkBox1";
this.checkBox1.Size = new System.Drawing.Size(82, 19);
this.checkBox1.TabIndex = 10;
this.checkBox1.Text = "randomize";
this.checkBox1.UseVisualStyleBackColor = true;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(627, 530);
this.Controls.Add(this.checkBox1);
this.Controls.Add(this.label8);
this.Controls.Add(this.ButtonAutoPublisherStart);
this.Controls.Add(this.ButtonAutoPublisherStop);
this.Controls.Add(this.trackBar1);
this.Controls.Add(this.label7);
this.Controls.Add(this.TextBoxSubscriber);
this.Controls.Add(this.label5);
this.Controls.Add(this.label4);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.ButtonServerStop);
this.Controls.Add(this.ButtonServerStart);
this.Controls.Add(this.TextBoxPort);
this.Controls.Add(this.label1);
this.Controls.Add(this.TextBoxTopicPublished);
this.Controls.Add(this.ButtonPublisherStop);
this.Controls.Add(this.ButtonPublisherStart);
this.Controls.Add(this.TextBoxPublish);
this.Controls.Add(this.ButtonPublish);
this.Controls.Add(this.ButtonSubscriberStop);
this.Controls.Add(this.ButtonSubscriberStart);
this.Controls.Add(this.ButtonGeneratePublishedMessage);
this.Controls.Add(this.label6);
this.Controls.Add(this.TextBoxTopicSubscribed);
this.Controls.Add(this.ButtonSubscribe);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Name = "Form1";
this.Text = "MQTT Testing";
((System.ComponentModel.ISupportInitialize)(this.trackBar1)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox TextBoxPort;
private System.Windows.Forms.Button ButtonServerStart;
private System.Windows.Forms.Button ButtonServerStop;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.MaskedTextBox maskedTextBox1;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.Button ButtonPublisherStop;
private System.Windows.Forms.Button ButtonPublisherStart;
private System.Windows.Forms.TextBox TextBoxPublish;
private System.Windows.Forms.Button ButtonPublish;
private System.Windows.Forms.Button ButtonSubscriberStop;
private System.Windows.Forms.Button ButtonSubscriberStart;
private System.Windows.Forms.TextBox TextBoxSubscriber;
private System.Windows.Forms.Button ButtonGeneratePublishedMessage;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.TextBox TextBoxTopicPublished;
private System.Windows.Forms.Button ButtonSubscribe;
private System.Windows.Forms.TextBox TextBoxTopicSubscribed;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.TrackBar trackBar1;
private System.Windows.Forms.Button ButtonAutoPublisherStop;
private System.Windows.Forms.Button ButtonAutoPublisherStart;
private System.Windows.Forms.Label label8;
private System.Windows.Forms.CheckBox checkBox1;
}
}

View File

@ -0,0 +1,476 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Form1.cs" company="Haemmer Electronics">
// Copyright (c) 2020 All rights reserved.
// </copyright>
// <summary>
// The main form.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace MQTTnet.TestApp.WinForm
{
using System;
using System.Text;
using System.Timers;
using System.Windows.Forms;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options;
using MQTTnet.Client.Receiving;
using MQTTnet.Extensions.ManagedClient;
using MQTTnet.Formatter;
using MQTTnet.Protocol;
using MQTTnet.Server;
using Newtonsoft.Json;
using Timer = System.Timers.Timer;
/// <summary>
/// The main form.
/// </summary>
public partial class Form1 : Form
{
/// <summary>
/// The managed publisher client.
/// </summary>
private IManagedMqttClient managedMqttClientPublisher;
/// <summary>
/// The managed subscriber client.
/// </summary>
private IManagedMqttClient managedMqttClientSubscriber;
/// <summary>
/// The MQTT server.
/// </summary>
private IMqttServer mqttServer;
/// <summary>
/// The port.
/// </summary>
private string port = "1883";
private readonly Random random;
private readonly Timer randomPublisherTimer;
/// <summary>
/// Initializes a new instance of the <see cref="Form1"/> class.
/// </summary>
public Form1()
{
this.InitializeComponent();
var timer = new Timer
{
AutoReset = true, Enabled = true, Interval = 1000
};
timer.Elapsed += this.TimerElapsed;
random = new Random();
randomPublisherTimer = new Timer
{
AutoReset = true,
Enabled = false,
};
randomPublisherTimer.Elapsed += (_, __) => this.BeginInvoke((MethodInvoker)delegate
{
if (checkBox1.Checked)
ButtonGeneratePublishedMessageClick(ButtonGeneratePublishedMessage, EventArgs.Empty);
ButtonPublishClick(ButtonPublish, EventArgs.Empty);
});
}
/// <summary>
/// Handles the publisher connected event.
/// </summary>
/// <param name="x">The MQTT client connected event args.</param>
private void OnPublisherConnected(MqttClientConnectedEventArgs x)
{
var item = "Publisher Connected";
this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; });
}
/// <summary>
/// Handles the publisher disconnected event.
/// </summary>
/// <param name="x">The MQTT client disconnected event args.</param>
private void OnPublisherDisconnected(MqttClientDisconnectedEventArgs x)
{
var item = "Publisher Disconnected";
this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; });
}
/// <summary>
/// Handles the subscriber connected event.
/// </summary>
/// <param name="x">The MQTT client connected event args.</param>
private void OnSubscriberConnected(MqttClientConnectedEventArgs x)
{
var item = "Subscriber Connected";
this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; });
}
/// <summary>
/// Handles the subscriber disconnected event.
/// </summary>
/// <param name="x">The MQTT client disconnected event args.</param>
private void OnSubscriberDisconnected(MqttClientDisconnectedEventArgs x)
{
var item = "Subscriber Disconnected";
this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; });
}
/// <summary>
/// The method that handles the button click to generate a message.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private void ButtonGeneratePublishedMessageClick(object sender, EventArgs e)
{
var message = new
{
tag = Guid.NewGuid(),
probability = random.NextDouble(),
};
var json = JsonConvert.SerializeObject(message);
this.TextBoxPublish.Text = json;
}
/// <summary>
/// The method that handles the button click to publish a message.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private async void ButtonPublishClick(object sender, EventArgs e)
{
((Button)sender).Enabled = false;
try
{
var payload = Encoding.UTF8.GetBytes(this.TextBoxPublish.Text);
var message = new MqttApplicationMessageBuilder().WithTopic(this.TextBoxTopicPublished.Text.Trim()).WithPayload(payload).WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce).WithRetainFlag().Build();
if (this.managedMqttClientPublisher != null)
{
await this.managedMqttClientPublisher.PublishAsync(message);
}
}
catch (Exception ex)
{
var item = ex.Message;
this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; });
}
((Button)sender).Enabled = true;
}
/// <summary>
/// The method that handles the button click to start the publisher.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private async void ButtonPublisherStartClick(object sender, EventArgs e)
{
var mqttFactory = new MqttFactory();
var tlsOptions = new MqttClientTlsOptions
{
UseTls = false, IgnoreCertificateChainErrors = true, IgnoreCertificateRevocationErrors = true, AllowUntrustedCertificates = true
};
var options = new MqttClientOptions
{
ClientId = "ClientPublisher",
ProtocolVersion = MqttProtocolVersion.V311,
ChannelOptions = new MqttClientTcpOptions
{
Server = "localhost", Port = int.Parse(this.TextBoxPort.Text.Trim()), TlsOptions = tlsOptions
}
};
if (options.ChannelOptions == null)
{
throw new InvalidOperationException();
}
options.Credentials = new MqttClientCredentials
{
Username = "username", Password = Encoding.UTF8.GetBytes("password")
};
options.CleanSession = true;
options.KeepAlivePeriod = TimeSpan.FromSeconds(5);
this.managedMqttClientPublisher = mqttFactory.CreateManagedMqttClient();
this.managedMqttClientPublisher.UseApplicationMessageReceivedHandler(this.HandleReceivedApplicationMessage);
this.managedMqttClientPublisher.ConnectedHandler = new MqttClientConnectedHandlerDelegate(OnPublisherConnected);
this.managedMqttClientPublisher.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(OnPublisherDisconnected);
await this.managedMqttClientPublisher.StartAsync(
new ManagedMqttClientOptions
{
ClientOptions = options
});
}
/// <summary>
/// The method that handles the button click to stop the publisher.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private async void ButtonPublisherStopClick(object sender, EventArgs e)
{
if (this.managedMqttClientPublisher == null)
{
return;
}
await this.managedMqttClientPublisher.StopAsync();
this.managedMqttClientPublisher = null;
}
/// <summary>
/// The method that handles the button click to start the server.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private async void ButtonServerStartClick(object sender, EventArgs e)
{
if (this.mqttServer != null)
{
return;
}
var storage = new JsonServerStorage();
storage.Clear();
this.mqttServer = new MqttFactory().CreateMqttServer();
var options = new MqttServerOptions();
options.DefaultEndpointOptions.Port = int.Parse(this.TextBoxPort.Text);
options.Storage = storage;
options.EnablePersistentSessions = true;
options.ConnectionValidator = new MqttServerConnectionValidatorDelegate(
c =>
{
if (c.ClientId.Length < 10)
{
c.ReasonCode = MqttConnectReasonCode.ClientIdentifierNotValid;
return;
}
if (c.Username != "username")
{
c.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
return;
}
if (c.Password != "password")
{
c.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
return;
}
c.ReasonCode = MqttConnectReasonCode.Success;
});
try
{
await this.mqttServer.StartAsync(options);
}
catch (Exception ex)
{
var item = ex.Message;
this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; });
await this.mqttServer.StopAsync();
this.mqttServer = null;
}
}
/// <summary>
/// The method that handles the button click to stop the server.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private async void ButtonServerStopClick(object sender, EventArgs e)
{
if (this.mqttServer == null)
{
return;
}
await this.mqttServer.StopAsync();
this.mqttServer = null;
}
/// <summary>
/// The method that handles the button click to subscribe to a certain topic.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private async void ButtonSubscribeClick(object sender, EventArgs e)
{
var topicFilter = new MqttTopicFilter { Topic = this.TextBoxTopicSubscribed.Text.Trim() };
await this.managedMqttClientSubscriber.SubscribeAsync(topicFilter);
var item = "Topic " + this.TextBoxTopicSubscribed.Text.Trim() + " is subscribed";
this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; });
}
/// <summary>
/// The method that handles the button click to start the subscriber.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private async void ButtonSubscriberStartClick(object sender, EventArgs e)
{
var mqttFactory = new MqttFactory();
var tlsOptions = new MqttClientTlsOptions
{
UseTls = false, IgnoreCertificateChainErrors = true, IgnoreCertificateRevocationErrors = true, AllowUntrustedCertificates = true
};
var options = new MqttClientOptions
{
ClientId = "ClientSubscriber",
ProtocolVersion = MqttProtocolVersion.V311,
ChannelOptions = new MqttClientTcpOptions
{
Server = "localhost", Port = int.Parse(this.TextBoxPort.Text.Trim()), TlsOptions = tlsOptions
}
};
if (options.ChannelOptions == null)
{
throw new InvalidOperationException();
}
options.Credentials = new MqttClientCredentials
{
Username = "username",
Password = Encoding.UTF8.GetBytes("password")
};
options.CleanSession = true;
options.KeepAlivePeriod = TimeSpan.FromSeconds(5);
this.managedMqttClientSubscriber = mqttFactory.CreateManagedMqttClient();
this.managedMqttClientSubscriber.ConnectedHandler = new MqttClientConnectedHandlerDelegate(OnSubscriberConnected);
this.managedMqttClientSubscriber.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(OnSubscriberDisconnected);
this.managedMqttClientSubscriber.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(this.OnSubscriberMessageReceived);
await this.managedMqttClientSubscriber.StartAsync(
new ManagedMqttClientOptions
{
ClientOptions = options
});
}
/// <summary>
/// The method that handles the button click to stop the subscriber.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private async void ButtonSubscriberStopClick(object sender, EventArgs e)
{
if (this.managedMqttClientSubscriber == null)
{
return;
}
await this.managedMqttClientSubscriber.StopAsync();
this.managedMqttClientSubscriber = null;
}
/// <summary>
/// Handles the received application message event.
/// </summary>
/// <param name="x">The MQTT application message received event args.</param>
private void HandleReceivedApplicationMessage(MqttApplicationMessageReceivedEventArgs x)
{
var item = $"Timestamp: {DateTime.Now:O} | Topic: {x.ApplicationMessage.Topic} | Payload: {x.ApplicationMessage.ConvertPayloadToString()} | QoS: {x.ApplicationMessage.QualityOfServiceLevel}";
this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; });
}
/// <summary>
/// Handles the received subscriber message event.
/// </summary>
/// <param name="x">The MQTT application message received event args.</param>
private void OnSubscriberMessageReceived(MqttApplicationMessageReceivedEventArgs x)
{
var item = $"Timestamp: {DateTime.Now:O} | Topic: {x.ApplicationMessage.Topic} | Payload: {x.ApplicationMessage.ConvertPayloadToString()} | QoS: {x.ApplicationMessage.QualityOfServiceLevel}";
this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; });
}
/// <summary>
/// The method that handles the text changes in the text box.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private void TextBoxPortTextChanged(object sender, EventArgs e)
{
// ReSharper disable once StyleCop.SA1126
if (int.TryParse(this.TextBoxPort.Text, out _))
{
this.port = this.TextBoxPort.Text.Trim();
}
else
{
this.TextBoxPort.Text = this.port;
this.TextBoxPort.SelectionStart = this.TextBoxPort.Text.Length;
this.TextBoxPort.SelectionLength = 0;
}
}
/// <summary>
/// The method that handles the timer events.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
this.BeginInvoke(
(MethodInvoker)delegate
{
// Server
this.TextBoxPort.Enabled = this.mqttServer == null;
this.ButtonServerStart.Enabled = this.mqttServer == null;
this.ButtonServerStop.Enabled = this.mqttServer != null;
// Publisher
this.ButtonPublisherStart.Enabled = this.managedMqttClientPublisher == null;
this.ButtonPublisherStop.Enabled = this.managedMqttClientPublisher != null;
// Auto Publisher
this.ButtonAutoPublisherStart.Enabled = !this.randomPublisherTimer.Enabled;
this.ButtonAutoPublisherStop.Enabled = this.randomPublisherTimer.Enabled;
// Subscriber
this.ButtonSubscriberStart.Enabled = this.managedMqttClientSubscriber == null;
this.ButtonSubscriberStop.Enabled = this.managedMqttClientSubscriber != null;
});
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
this.label8.Text = $"{this.trackBar1.Value:N0} ms";
this.randomPublisherTimer.Interval = this.trackBar1.Value;
}
private void ButtonAutoPublisherStartClick(object sender, EventArgs e)
{
((Button)sender).Enabled = false;
this.randomPublisherTimer.Start();
((Button)sender).Enabled = true;
}
private void ButtonAutoPublisherStopClick(object sender, EventArgs e)
{
((Button)sender).Enabled = false;
this.randomPublisherTimer.Stop();
((Button)sender).Enabled = true;
}
}
}

View File

@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,83 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="JsonServerStorage.cs" company="Haemmer Electronics">
// Copyright (c) 2020 All rights reserved.
// </copyright>
// <summary>
// The JSON server storage.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace MQTTnet.TestApp.WinForm
{
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using MQTTnet.Server;
using Newtonsoft.Json;
/// <inheritdoc cref="IMqttServerStorage"/>
/// <summary>
/// The JSON server storage.
/// </summary>
/// <seealso cref="IMqttServerStorage"/>
public class JsonServerStorage : IMqttServerStorage
{
/// <summary>
/// The file name.
/// </summary>
private readonly string filename = Path.Combine(Directory.GetCurrentDirectory(), "Retained.json");
/// <summary>
/// Clears the file.
/// </summary>
public void Clear()
{
if (File.Exists(this.filename))
{
File.Delete(this.filename);
}
}
/// <inheritdoc cref="IMqttServerStorage"/>
/// <summary>
/// Loads the retained messages.
/// </summary>
/// <returns>A <see cref="IList{T}"/> of <see cref="MqttApplicationMessage"/>.</returns>
/// <seealso cref="IMqttServerStorage"/>
public async Task<IList<MqttApplicationMessage>> LoadRetainedMessagesAsync()
{
await Task.CompletedTask;
if (!File.Exists(this.filename))
{
return new List<MqttApplicationMessage>();
}
try
{
var json = await File.ReadAllTextAsync(this.filename);
return JsonConvert.DeserializeObject<List<MqttApplicationMessage>>(json);
}
catch
{
return new List<MqttApplicationMessage>();
}
}
/// <inheritdoc cref="IMqttServerStorage"/>
/// <summary>
/// Saves the retained messages to a file.
/// </summary>
/// <param name="messages">The messages.</param>
/// <returns>A <see cref="Task"/> representing any asynchronous operation.</returns>
/// <seealso cref="IMqttServerStorage"/>
public async Task SaveRetainedMessagesAsync(IList<MqttApplicationMessage> messages)
{
await Task.CompletedTask;
var json = JsonConvert.SerializeObject(messages);
await File.WriteAllTextAsync(this.filename, json);
}
}
}

View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RootNamespace>MQTTnet.TestApp.WinForm</RootNamespace>
<AssemblyName>MQTTnet.TestApp.WinForm</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="GitVersionTask" Version="5.5.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MQTTnet" Version="3.0.13" />
<PackageReference Include="MQTTnet.Extensions.ManagedClient" Version="3.0.13" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,45 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Program.cs" company="Haemmer Electronics">
// Copyright (c) 2020 All rights reserved.
// </copyright>
// <summary>
// The main program.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace MQTTnet.TestApp.WinForm
{
using System;
using System.Threading;
using System.Windows.Forms;
/// <summary>
/// The main program.
/// </summary>
internal static class Program
{
static readonly Mutex mutex = new Mutex(true, "{B9D725A5-48F1-4907-974F-B6C3B9C8C4BB}");
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main()
{
if (!mutex.WaitOne(TimeSpan.Zero, true))
return;
try
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
finally
{
mutex.ReleaseMutex();
}
}
}
}

221
cnc.nswag Normal file

File diff suppressed because one or more lines are too long

272
cnc.yml Normal file
View File

@ -0,0 +1,272 @@
openapi: 3.0.3
info:
title: Command and Control Service
description: This service s responsible for controlling and handling information
about IoT devices in the Birbnetes system.
contact:
email: tormakristof@tormakristof.eu
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
version: 1.0.0
servers:
- url: https://birb.k8s.kmlabz.com
tags:
- name: cnc
description: Command and Control Service interaction
paths:
/devices:
get:
tags:
- cnc
summary: Get all device info
operationId: getall
responses:
200:
description: Array of devices
content:
application/json:
schema:
$ref: '#/components/schemas/ListOfDevices'
404:
description: No device found
content: {}
/devices/offline:
post:
tags:
- cnc
summary: Shut down all devices
operationId: offlineall
responses:
200:
description: Message sent
content: {}
500:
description: Message sending unsuccessful
content: {}
/devices/online:
post:
tags:
- cnc
summary: Bring all devices online
operationId: onlineall
responses:
200:
description: Message sent
content: {}
500:
description: Message sending unsuccessful
content: {}
/devices/{deviceID}:
get:
tags:
- cnc
summary: Get all device info
operationId: getdevice
parameters:
- name: deviceID
in: path
description: ID of device to query
required: true
schema:
type: string
format: uuid
responses:
200:
description: Information about a particular device
content:
application/json:
schema:
$ref: '#/components/schemas/Device'
404:
description: Device not found
content: {}
/devices/{deviceID}/offline:
post:
tags:
- cnc
summary: Shut down device
operationId: offlinedevice
parameters:
- name: deviceID
in: path
description: ID of device to shut down
required: true
schema:
type: string
format: uuid
responses:
200:
description: Message sent
content: {}
500:
description: Message sending unsuccessful
content: {}
/devices/{deviceID}/online:
post:
tags:
- cnc
summary: Bring device online
operationId: onlinedevice
parameters:
- name: deviceID
in: path
description: ID of device to bring online
required: true
schema:
type: string
format: uuid
responses:
200:
description: Message sent
content: {}
500:
description: Message sending unsuccessful
content: {}
/devices/{deviceID}/{sensorID}:
get:
tags:
- cnc
summary: Get info about a particular device's sensor
operationId: getsensor
parameters:
- name: deviceID
in: path
description: ID of device to query
required: true
schema:
type: string
format: uuid
- name: sensorID
in: path
description: ID of sensor to query
required: true
schema:
type: string
format: uuid
responses:
200:
description: Information about a sensor
content:
application/json:
schema:
$ref: '#/components/schemas/Sensor'
404:
description: Device or sensor not found
content: {}
/devices/{deviceID}/{sensorID}/offline:
post:
tags:
- cnc
summary: Shut down sensor
operationId: offlinesensor
parameters:
- name: deviceID
in: path
description: ID of device to query
required: true
schema:
type: string
format: uuid
- name: sensorID
in: path
description: ID of sensor to query
required: true
schema:
type: string
format: uuid
responses:
200:
description: Message sent
content: {}
500:
description: Message sending unsuccessful
content: {}
/devices/{deviceID}/{sensorID}/online:
post:
tags:
- cnc
summary: Bring sensor online
operationId: onlinesensor
parameters:
- name: deviceID
in: path
description: ID of device to query
required: true
schema:
type: string
format: uuid
- name: sensorID
in: path
description: ID of sensor to query
required: true
schema:
type: string
format: uuid
responses:
200:
description: Message sent
content: {}
500:
description: Message sending unsuccessful
content: {}
components:
schemas:
ListOfDevices:
type: array
items:
$ref: '#/components/schemas/Device'
Device:
required:
- id
- sensors
- status
- url
- coordinates
type: object
properties:
id:
type: string
format: uuid
status:
type: string
enum:
- online
- error
- offline
url:
type: string
format: url
coordinates:
required:
- latitude
- longitude
type: object
properties:
latitude:
type: number
format: double
longitude:
type: number
format: double
sensors:
$ref: '#/components/schemas/ArrayofSensors'
ArrayofSensors:
type: array
items:
$ref: '#/components/schemas/Sensor'
Sensor:
required:
- id
- status
type: object
properties:
id:
type: string
format: uuid
status:
type: string
enum:
- online
- unknown
- offline

BIN
docs/Dashboard.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
docs/Login.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
docs/Trello_Birdmap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

98
input.nswag Normal file
View File

@ -0,0 +1,98 @@
{
"runtime": "NetCore31",
"defaultVariables": null,
"documentGenerator": {
"fromDocument": {
"json": "openapi: 3.0.3\ninfo:\n title: Input Service\n description: This is the input interface of the Birbnetes system.\n contact:\n email: tormakristof@tormakristof.eu\n license:\n name: Apache 2.0\n url: http://www.apache.org/licenses/LICENSE-2.0.html\n version: 1.1.3\nservers:\n- url: https://birb.k8s.kmlabz.com\ntags:\n- name: input\n description: Input Service interaction\npaths:\n /sample:\n get:\n tags:\n - input\n summary: Get all stored input queries\n operationId: getall\n responses:\n 200:\n description: Array of input objects\n content:\n application/json:\n schema:\n $ref: '#/components/schemas/InputResponse'\n 404:\n description: No object matching filter\n content:\n application/json:\n schema:\n $ref: '#/components/schemas/ApiResponse'\n post:\n tags:\n - input\n summary: uploads a sample into the system\n operationId: uploadFile\n requestBody:\n content:\n multipart/form-data:\n schema:\n required:\n - description\n - file\n properties:\n description:\n type: object\n description: Metadata json\n properties:\n deviceid:\n type: string\n date:\n type: string\n format: date\n file:\n type: string\n description: Wave file to upload\n format: binary\n required: true\n responses:\n 200:\n description: successful operation\n content:\n application/json:\n schema:\n $ref: '#/components/schemas/ApiResponse'\n 400:\n description: JSON parse error\n content:\n application/json:\n schema:\n $ref: '#/components/schemas/ApiResponse'\n 415:\n description: Media type error\n content:\n application/json:\n schema:\n $ref: '#/components/schemas/ApiResponse'\n 417:\n description: JSON invalid schema\n content:\n application/json:\n schema:\n $ref: '#/components/schemas/ApiResponse'\n 469:\n description: No file found\n content:\n application/json:\n schema:\n $ref: '#/components/schemas/ApiResponse'\n 470:\n description: Description missing\n content:\n application/json:\n schema:\n $ref: '#/components/schemas/ApiResponse'\n /sample/{tagID}:\n get:\n tags:\n - input\n summary: Get input object by ID\n operationId: getInput\n parameters:\n - name: tagID\n in: path\n description: ID of input object file\n required: true\n schema:\n type: string\n format: uuid\n responses:\n 200:\n description: input object\n content:\n application/json:\n schema:\n $ref: '#/components/schemas/InputSingeResponse'\n 404:\n description: Tag not found\n content:\n application/json:\n schema:\n $ref: '#/components/schemas/ApiResponse'\ncomponents:\n schemas:\n InputSingeResponse:\n required:\n - message\n - status\n type: object\n properties:\n status:\n type: string\n message:\n $ref: '#/components/schemas/InputObject'\n InputResponse:\n type: array\n items:\n $ref: '#/components/schemas/InputObject'\n InputObject:\n required:\n - date\n - device_id\n - tag\n type: object\n properties:\n tag:\n type: string\n format: uuid\n date:\n type: string\n format: date\n device_id:\n type: integer\n ApiResponse:\n required:\n - message\n - status\n type: object\n properties:\n status:\n type: string\n message:\n type: string\n",
"url": "https://git.kmlabz.com/birbnetes/swagger-docs/raw/branch/master/input.yml",
"output": null,
"newLineBehavior": "Auto"
}
},
"codeGenerators": {
"openApiToCSharpClient": {
"clientBaseClass": null,
"configurationClass": null,
"generateClientClasses": true,
"generateClientInterfaces": true,
"clientBaseInterface": null,
"injectHttpClient": true,
"disposeHttpClient": true,
"protectedMethods": [],
"generateExceptionClasses": true,
"exceptionClass": "ApiException",
"wrapDtoExceptions": true,
"useHttpClientCreationMethod": false,
"httpClientType": "System.Net.Http.HttpClient",
"useHttpRequestMessageCreationMethod": false,
"useBaseUrl": true,
"generateBaseUrlProperty": true,
"generateSyncMethods": false,
"exposeJsonSerializerSettings": false,
"clientClassAccessModifier": "public",
"typeAccessModifier": "public",
"generateContractsOutput": false,
"contractsNamespace": null,
"contractsOutputFilePath": null,
"parameterDateTimeFormat": "s",
"parameterDateFormat": "yyyy-MM-dd",
"generateUpdateJsonSerializerSettingsMethod": true,
"useRequestAndResponseSerializationSettings": false,
"serializeTypeInformation": false,
"queryNullValue": "",
"className": "InputService",
"operationGenerationMode": "MultipleClientsFromOperationId",
"additionalNamespaceUsages": [],
"additionalContractNamespaceUsages": [],
"generateOptionalParameters": false,
"generateJsonMethods": false,
"enforceFlagEnums": false,
"parameterArrayType": "System.Collections.Generic.IEnumerable",
"parameterDictionaryType": "System.Collections.Generic.IDictionary",
"responseArrayType": "System.Collections.Generic.ICollection",
"responseDictionaryType": "System.Collections.Generic.IDictionary",
"wrapResponses": false,
"wrapResponseMethods": [],
"generateResponseClasses": true,
"responseClass": "SwaggerResponse",
"namespace": "Birdmap.BLL.Services",
"requiredPropertiesMustBeDefined": true,
"dateType": "System.DateTimeOffset",
"jsonConverters": null,
"anyType": "object",
"dateTimeType": "System.DateTimeOffset",
"timeType": "System.TimeSpan",
"timeSpanType": "System.TimeSpan",
"arrayType": "System.Collections.Generic.ICollection",
"arrayInstanceType": "System.Collections.ObjectModel.Collection",
"dictionaryType": "System.Collections.Generic.IDictionary",
"dictionaryInstanceType": "System.Collections.Generic.Dictionary",
"arrayBaseType": "System.Collections.ObjectModel.Collection",
"dictionaryBaseType": "System.Collections.Generic.Dictionary",
"classStyle": "Poco",
"generateDefaultValues": true,
"generateDataAnnotations": true,
"excludedTypeNames": [],
"excludedParameterNames": [],
"handleReferences": false,
"generateImmutableArrayProperties": false,
"generateImmutableDictionaryProperties": false,
"jsonSerializerSettingsTransformationMethod": null,
"inlineNamedArrays": false,
"inlineNamedDictionaries": false,
"inlineNamedTuples": true,
"inlineNamedAny": false,
"generateDtoTypes": true,
"generateOptionalPropertiesAsNullable": false,
"generateNullableReferenceTypes": false,
"templateDirectory": null,
"typeNameGeneratorType": null,
"propertyNameGeneratorType": null,
"enumNameGeneratorType": null,
"serviceHost": null,
"serviceSchemes": null,
"output": null,
"newLineBehavior": "Auto"
}
}
}

167
input.yml Normal file
View File

@ -0,0 +1,167 @@
openapi: 3.0.3
info:
title: Input Service
description: This is the input interface of the Birbnetes system.
contact:
email: tormakristof@tormakristof.eu
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
version: 1.1.3
servers:
- url: https://birb.k8s.kmlabz.com
tags:
- name: input
description: Input Service interaction
paths:
/sample:
get:
tags:
- input
summary: Get all stored input queries
operationId: getall
responses:
200:
description: Array of input objects
content:
application/json:
schema:
$ref: '#/components/schemas/InputResponse'
404:
description: No object matching filter
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
post:
tags:
- input
summary: uploads a sample into the system
operationId: uploadFile
requestBody:
content:
multipart/form-data:
schema:
required:
- description
- file
properties:
description:
type: object
description: Metadata json
properties:
deviceid:
type: string
date:
type: string
format: date
file:
type: string
description: Wave file to upload
format: binary
required: true
responses:
200:
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
400:
description: JSON parse error
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
415:
description: Media type error
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
417:
description: JSON invalid schema
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
469:
description: No file found
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
470:
description: Description missing
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
/sample/{tagID}:
get:
tags:
- input
summary: Get input object by ID
operationId: getInput
parameters:
- name: tagID
in: path
description: ID of input object file
required: true
schema:
type: string
format: uuid
responses:
200:
description: input object
content:
application/json:
schema:
$ref: '#/components/schemas/InputSingeResponse'
404:
description: Tag not found
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
components:
schemas:
InputSingeResponse:
required:
- message
- status
type: object
properties:
status:
type: string
message:
$ref: '#/components/schemas/InputObject'
InputResponse:
type: array
items:
$ref: '#/components/schemas/InputObject'
InputObject:
required:
- date
- device_id
- tag
type: object
properties:
tag:
type: string
format: uuid
date:
type: string
format: date
device_id:
type: integer
ApiResponse:
required:
- message
- status
type: object
properties:
status:
type: string
message:
type: string