From c0c82e7c9c1963a97ebfd1d4d3e2be15463ac342 Mon Sep 17 00:00:00 2001 From: Adam <897017+aSemy@users.noreply.github.com> Date: Sat, 2 Jul 2022 08:45:21 +0200 Subject: [PATCH] finish migrating to ktor! - remove http4k - renamed 'schema' subproject to 'library', because it contains more than just data models - tiles are now hosted per factorio-server - changed api base to `kafkatorio/data` - tidied up some Gradle conf - remove 'events-processor' subproject - I don't want to set up loads of microservices right now --- gradle/kotlin-js-store/yarn.lock | 814 +++++++++++++++++- gradle/libs.versions.toml | 2 +- .../build.gradle.kts | 6 + .../dev/adamko/kafkatorio/library}/json.kt | 3 +- .../adamko/kafkatorio/library}/kxsBinary.kt | 2 +- .../kafkatorio/schema/common/colours.kt | 0 .../kafkatorio/schema/common/factorioIds.kt | 0 .../schema/common/factorioPrototypes.kt | 0 .../kafkatorio/schema/common/mapTile.kt | 0 .../kafkatorio/schema/common/positions.kt | 0 .../kafkatorio/schema/common/resources.kt | 0 .../schema/packets/eventServerPacket.kt | 0 .../schema/packets/kafkatorioPacket.kt | 0 .../schema/packets/kafkatorioPacketInstant.kt | 0 .../schema/packets/kafkatorioPacketKeyed.kt | 0 .../kafkatorio/events/schema/ColourHexTest.kt | 3 +- .../events/schema/MapChunkUpdateTest.kt | 0 .../events/schema/PrototypesTest.kt | 0 .../events/schema/UpdatePacketsTest.kt | 0 .../common/MapChunkPositionBoundsTest.kt | 0 .../schema/common/MapChunkPositionTest.kt | 0 .../schema/common/MapTileDictionaryTest.kt | 0 .../schema/common/MapTilePositionTest.kt | 0 .../schema/packets/EntityUpdateTest.kt | 0 .../events/schema/ValueClassTransformer.kt | 0 .../adamko/kafkatorio/events/schema/kt2ts.kt | 0 .../adamko/kafkatorio/events/schema/kt2ts2.kt | 0 .../kafkatorio/library}/FileEventsFlow.kt | 0 .../kafkatorio/library}/KxsBinaryTests.kt | 19 +- .../schema/common}/MapTileDictionaryTest.kt | 5 +- modules/events-mod/build.gradle.kts | 2 +- modules/events-processor/build.gradle.kts | 125 --- modules/events-server/.gitignore | 2 +- modules/events-server/build.gradle.kts | 23 +- .../kafkatorio/processor/eventProcessor.kt | 58 -- .../tileserver/SyslogSocketServer.kt | 328 +++---- .../processor/tileserver/WebMapTileServer.kt | 168 ++-- .../processor/tileserver/WebServer.kt | 30 +- .../processor/tileserver/WebsocketServer.kt | 280 +++--- .../config/ApplicationProperties.kt | 2 +- .../{processor => server}/config/PortVal.kt | 6 +- .../serdes => server/config}/kxsJson.kt | 5 +- .../adamko/kafkatorio/server/eventsServer.kt | 32 + .../server/kafkatorioEventsServer.kt | 38 - .../processor}/DebounceProcessor.kt | 2 +- .../processor/KafkatorioTopology.kt | 21 +- .../processor/StreamsExceptionHandler.kt | 2 +- .../processor/admin/KafkatorioKafkaAdmin.kt | 5 +- .../server/processor/eventProcessor.kt | 37 + .../processor}/kafkatorioTopics.kt | 2 +- .../processor/topology/colourMapChunks.kt | 10 +- .../topology/factorioServerPackets.kt | 9 +- .../{ => server}/processor/topology/model.kt | 2 +- .../processor/topology/packetDataStreams.kt | 6 +- .../processor/topology/prototypes.kt | 4 +- .../processor/topology/saveMapTiles.kt | 10 +- .../topology/websocketBroadcaster.kt} | 15 +- .../kafkatorio/server/socket/SyslogMsg.kt | 63 ++ .../server/socket/SyslogSocketServer.kt | 99 +++ .../kafkatorio/server/syslogSocketServer.kt | 152 ---- .../server/web/rest/factorioServersRoutes.kt | 121 +++ .../kafkatorio/server/web/rest/restApi.kt | 50 ++ .../adamko/kafkatorio/server/web/webServer.kt | 27 + .../web/websocket/WebmapWebsocketServer.kt | 112 +++ .../server/web/websocket/wsServer.kt | 34 + .../kafkatorio/server/webmapTileServer.kt | 148 ---- .../server/webmapWebsocketServer.kt | 130 --- .../src/main/resources/config.yml | 4 +- .../processor/misc/DebounceProcessorTest.kt | 49 -- .../kafkatorio/processor/misc/serdeSize.kt | 6 +- .../processor/topology/GroupMapChunksTest.kt | 6 +- .../processor/topology/SaveMapChunksTest.kt | 4 +- .../src/docker-compose.yml | 2 +- modules/web-map/build.gradle.kts | 50 +- .../dev/adamko/kafkatorio/webmap/App.kt | 9 +- .../webmap/ApplicationProperties.kt | 2 +- .../kafkatorio/webmap/externals/leaflet.kt | 1 + .../dev/adamko/kafkatorio/webmap/json.kt | 2 +- .../dev/adamko/kafkatorio/webmap/map.kt | 6 +- settings.gradle.kts | 3 +- 80 files changed, 1878 insertions(+), 1280 deletions(-) rename modules/{events-schema => events-library}/build.gradle.kts (93%) rename modules/{events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema => events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/library}/json.kt (98%) rename modules/{events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/serdes => events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/library}/kxsBinary.kt (99%) rename modules/{events-schema => events-library}/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/colours.kt (100%) rename modules/{events-schema => events-library}/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioIds.kt (100%) rename modules/{events-schema => events-library}/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioPrototypes.kt (100%) rename modules/{events-schema => events-library}/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/mapTile.kt (100%) rename modules/{events-schema => events-library}/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/positions.kt (100%) rename modules/{events-schema => events-library}/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/resources.kt (100%) rename modules/{events-schema => events-library}/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/eventServerPacket.kt (100%) rename modules/{events-schema => events-library}/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacket.kt (100%) rename modules/{events-schema => events-library}/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacketInstant.kt (100%) rename modules/{events-schema => events-library}/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacketKeyed.kt (100%) rename modules/{events-schema => events-library}/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/ColourHexTest.kt (97%) rename modules/{events-schema => events-library}/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/MapChunkUpdateTest.kt (100%) rename modules/{events-schema => events-library}/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/PrototypesTest.kt (100%) rename modules/{events-schema => events-library}/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/UpdatePacketsTest.kt (100%) rename modules/{events-schema => events-library}/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapChunkPositionBoundsTest.kt (100%) rename modules/{events-schema => events-library}/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapChunkPositionTest.kt (100%) rename modules/{events-schema => events-library}/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTileDictionaryTest.kt (100%) rename modules/{events-schema => events-library}/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTilePositionTest.kt (100%) rename modules/{events-schema => events-library}/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/packets/EntityUpdateTest.kt (100%) rename modules/{events-schema => events-library}/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/ValueClassTransformer.kt (100%) rename modules/{events-schema => events-library}/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts.kt (100%) rename modules/{events-schema => events-library}/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts2.kt (100%) rename modules/{events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/misc => events-library/src/jvmMain/kotlin/dev/adamko/kafkatorio/library}/FileEventsFlow.kt (100%) rename modules/{events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/misc => events-library/src/jvmTest/kotlin/dev/adamko/kafkatorio/library}/KxsBinaryTests.kt (97%) rename modules/{events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/serdes => events-library/src/jvmTest/kotlin/dev/adamko/kafkatorio/schema/common}/MapTileDictionaryTest.kt (89%) delete mode 100644 modules/events-processor/build.gradle.kts delete mode 100644 modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/eventProcessor.kt rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{processor => server}/config/ApplicationProperties.kt (95%) rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{processor => server}/config/PortVal.kt (72%) rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{processor/serdes => server/config}/kxsJson.kt (63%) create mode 100644 modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/eventsServer.kt delete mode 100644 modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/kafkatorioEventsServer.kt rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{processor/misc => server/processor}/DebounceProcessor.kt (98%) rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{ => server}/processor/KafkatorioTopology.kt (89%) rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{ => server}/processor/StreamsExceptionHandler.kt (91%) rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{ => server}/processor/admin/KafkatorioKafkaAdmin.kt (91%) create mode 100644 modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/eventProcessor.kt rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{processor/admin => server/processor}/kafkatorioTopics.kt (98%) rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{ => server}/processor/topology/colourMapChunks.kt (96%) rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{ => server}/processor/topology/factorioServerPackets.kt (90%) rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{ => server}/processor/topology/model.kt (93%) rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{ => server}/processor/topology/packetDataStreams.kt (86%) rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{ => server}/processor/topology/prototypes.kt (95%) rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{ => server}/processor/topology/saveMapTiles.kt (92%) rename modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/{processor/topology/websocketBroadcast.kt => server/processor/topology/websocketBroadcaster.kt} (86%) create mode 100644 modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/socket/SyslogMsg.kt create mode 100644 modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/socket/SyslogSocketServer.kt delete mode 100644 modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/syslogSocketServer.kt create mode 100644 modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/rest/factorioServersRoutes.kt create mode 100644 modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/rest/restApi.kt create mode 100644 modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/webServer.kt create mode 100644 modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/websocket/WebmapWebsocketServer.kt create mode 100644 modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/websocket/wsServer.kt delete mode 100644 modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/webmapTileServer.kt delete mode 100644 modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/webmapWebsocketServer.kt delete mode 100644 modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/misc/DebounceProcessorTest.kt rename modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/{ => server}/processor/topology/SaveMapChunksTest.kt (98%) diff --git a/gradle/kotlin-js-store/yarn.lock b/gradle/kotlin-js-store/yarn.lock index e117ebe..bc40042 100644 --- a/gradle/kotlin-js-store/yarn.lock +++ b/gradle/kotlin-js-store/yarn.lock @@ -24,6 +24,11 @@ resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.1.1.tgz#bf5d45611ab74890be386712a0e5d998c65ee2a1" integrity sha512-J/3yg2AIXc9wznaVqpHVX3Wa5jwKovVF0AMYSnbmcXTiL3PpRPfF58pzWucCwEiCJBp+hCNRLWClTomD8SseKg== +"@leichtgewicht/ip-codec@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" + integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== + "@popperjs/core@^2.11.4": version "2.11.5" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64" @@ -52,11 +57,41 @@ dependencies: html-parse-stringify "^3" +"@types/body-parser@*": + version "1.19.2" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" + integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/bonjour@^3.5.9": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.10.tgz#0f6aadfe00ea414edc86f5d106357cda9701e275" + integrity sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw== + dependencies: + "@types/node" "*" + "@types/component-emitter@^1.2.10": version "1.2.11" resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.11.tgz#50d47d42b347253817a39709fef03ce66a108506" integrity sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ== +"@types/connect-history-api-fallback@^1.3.5": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz#d1f7a8a09d0ed5a57aee5ae9c18ab9b803205dae" + integrity sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw== + dependencies: + "@types/express-serve-static-core" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + "@types/cookie@^0.4.1": version "0.4.1" resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" @@ -88,6 +123,25 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18": + version "4.17.29" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz#2a1795ea8e9e9c91b4a4bbe475034b20c1ec711c" + integrity sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express@*", "@types/express@^4.17.13": + version "4.17.13" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" + integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.18" + "@types/qs" "*" + "@types/serve-static" "*" + "@types/geojson@7946.0.8": version "7946.0.8" resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.8.tgz#30744afdb385e2945e22f3b033f897f76b1f12ca" @@ -108,11 +162,16 @@ dependencies: "@types/node" "*" -"@types/json-schema@*", "@types/json-schema@^7.0.8": +"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== +"@types/mime@^1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" + integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + "@types/minimatch@*": version "3.0.5" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" @@ -128,6 +187,50 @@ resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109" integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw== +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + +"@types/retry@0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" + integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== + +"@types/serve-index@^1.9.1": + version "1.9.1" + resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278" + integrity sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg== + dependencies: + "@types/express" "*" + +"@types/serve-static@*", "@types/serve-static@^1.13.10": + version "1.13.10" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" + integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/sockjs@^0.3.33": + version "0.3.33" + resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.33.tgz#570d3a0b99ac995360e3136fd6045113b1bd236f" + integrity sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw== + dependencies: + "@types/node" "*" + +"@types/ws@^8.5.1": + version "8.5.3" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" + integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w== + dependencies: + "@types/node" "*" + "@ungap/promise-all-settled@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" @@ -286,7 +389,7 @@ abab@^2.0.5: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== -accepts@~1.3.4: +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== @@ -304,11 +407,25 @@ acorn@^8.4.1, acorn@^8.5.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== +ajv-keywords@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + ajv@^6.12.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -319,11 +436,26 @@ ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.0.0, ajv@^8.8.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + ansi-colors@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== +ansi-html-community@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" + integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -356,6 +488,16 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +array-flatten@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + awesome-bootstrap-checkbox@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/awesome-bootstrap-checkbox/-/awesome-bootstrap-checkbox-1.0.1.tgz#dab10146b6001129ab0a0ec1e54bb77c6c30457a" @@ -371,12 +513,17 @@ base64id@2.0.0, base64id@~2.0.0: resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -body-parser@^1.19.0: +body-parser@1.20.0, body-parser@^1.19.0: version "1.20.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.0.tgz#3de69bd89011c11573d7bfee6a64f11b6bd27cc5" integrity sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg== @@ -394,6 +541,16 @@ body-parser@^1.19.0: type-is "~1.6.18" unpipe "1.0.0" +bonjour-service@^1.0.11: + version "1.0.13" + resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.0.13.tgz#4ac003dc1626023252d58adf2946f57e5da450c1" + integrity sha512-LWKRU/7EqDUC9CTAQtuZl5HzBALoCYwtLhffW3et7vZMwv3bWLpJf8bRYlMD5OCcDpTfnPgNCV4yo9ZIaJGMiA== + dependencies: + array-flatten "^2.1.2" + dns-equal "^1.0.0" + fast-deep-equal "^3.1.3" + multicast-dns "^7.2.5" + bootstrap-icons@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/bootstrap-icons/-/bootstrap-icons-1.8.1.tgz#773c1625bcbf3e86090ea9da4386c2c6459c5582" @@ -447,6 +604,11 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -492,7 +654,7 @@ chart.js@^3.8.0: resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.8.0.tgz#c6c14c457b9dc3ce7f1514a59e9b262afd6f1a94" integrity sha512-cr8xhrXjLIXVLOBZPkBZVF6NDeiVIrPLHcMhnON7UufudL+CNeRrD+wpYanswlm8NpudMdrt3CHoLMQMxJhHRg== -chokidar@3.5.3, chokidar@^3.5.1: +chokidar@3.5.3, chokidar@^3.5.1, chokidar@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -554,6 +716,11 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +colorette@^2.0.10: + version "2.0.19" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" + integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== + colorette@^2.0.14: version "2.0.16" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" @@ -579,11 +746,36 @@ component-emitter@~1.3.0: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +connect-history-api-fallback@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== + connect@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" @@ -594,16 +786,38 @@ connect@^3.7.0: parseurl "~1.3.3" utils-merge "1.0.1" +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + cookie@~0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + cors@~2.8.5: version "2.8.5" resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" @@ -662,7 +876,7 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4.3.4, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: +debug@4.3.4, debug@^4.1.0, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -674,16 +888,38 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== +default-gateway@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" + integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== + dependencies: + execa "^5.0.0" + +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + depd@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + destroy@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + di@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" @@ -694,6 +930,18 @@ diff@5.0.0: resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg== + +dns-packet@^5.2.2: + version "5.4.0" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.4.0.tgz#1f88477cf9f27e78a213fb6d118ae38e759a879b" + integrity sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g== + dependencies: + "@leichtgewicht/ip-codec" "^2.0.1" + dom-serialize@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" @@ -836,6 +1084,11 @@ estraverse@^5.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -846,12 +1099,64 @@ events@^3.2.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +express@^4.17.3: + version "4.18.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.18.1.tgz#7797de8b9c72c857b9cd0e14a5eea80666267caf" + integrity sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.0" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.5.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.10.3" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + extend@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -fast-deep-equal@^3.1.1: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== @@ -866,6 +1171,13 @@ fastest-levenshtein@^1.0.12: resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow== +faye-websocket@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + fecha@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" @@ -891,6 +1203,19 @@ finalhandler@1.1.2: statuses "~1.5.0" unpipe "~1.0.0" +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + find-up@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" @@ -927,6 +1252,16 @@ format-util@1.0.5: resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.5.tgz#1ffb450c8a03e7bccffe40643180918cc297d271" integrity sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg== +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + fs-extra@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" @@ -945,6 +1280,11 @@ fs-extra@^8.0.1: jsonfile "^4.0.0" universalify "^0.1.0" +fs-monkey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" + integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -979,6 +1319,11 @@ get-intrinsic@^1.0.2: has "^1.0.3" has-symbols "^1.0.1" +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + gettext-extract@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/gettext-extract/-/gettext-extract-2.0.1.tgz#4ade7e3d7c1c247d95a81f28059ca1923c355886" @@ -1060,6 +1405,11 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -1087,6 +1437,21 @@ he@1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ== + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-entities@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" + integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== + html-parse-stringify@^3: version "3.0.1" resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2" @@ -1094,6 +1459,11 @@ html-parse-stringify@^3: dependencies: void-elements "3.1.0" +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== + http-errors@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -1105,7 +1475,22 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" -"http-proxy-middleware@>=2.0.6 <3.0.0", http-proxy-middleware@^2.0.6: +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.5.1: + version "0.5.8" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" + integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== + +"http-proxy-middleware@>=2.0.6 <3.0.0", http-proxy-middleware@^2.0.3, http-proxy-middleware@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f" integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw== @@ -1125,6 +1510,11 @@ http-proxy@^1.18.1: follow-redirects "^1.0.0" requires-port "^1.0.0" +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -1168,16 +1558,31 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + interpret@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +ipaddr.js@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" + integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -1192,6 +1597,11 @@ is-core-module@^2.8.1: dependencies: has "^1.0.3" +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -1231,11 +1641,28 @@ is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-unicode-supported@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + isbinaryfile@^4.0.8: version "4.0.10" resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3" @@ -1282,6 +1709,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -1428,11 +1860,28 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= +memfs@^3.4.3: + version "3.4.7" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.7.tgz#e5252ad2242a724f938cb937e3c4f7ceb1f70e5a" + integrity sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw== + dependencies: + fs-monkey "^1.0.3" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + micromatch@^4.0.2: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" @@ -1441,23 +1890,38 @@ micromatch@^4.0.2: braces "^3.0.2" picomatch "^2.3.1" -mime-db@1.52.0: +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + mime@^2.5.2: version "2.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + minimatch@5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" @@ -1527,6 +1991,14 @@ ms@2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +multicast-dns@^7.2.5: + version "7.2.5" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" + integrity sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg== + dependencies: + dns-packet "^5.2.2" + thunky "^1.0.2" + nanoid@3.3.3, nanoid@^3.3.1: version "3.3.3" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" @@ -1542,6 +2014,11 @@ neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== +node-forge@^1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== + node-releases@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.3.tgz#225ee7488e4a5e636da8da52854844f9d716ca96" @@ -1552,6 +2029,13 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + object-assign@^4: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -1562,6 +2046,11 @@ object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + on-finished@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" @@ -1576,6 +2065,11 @@ on-finished@~2.3.0: dependencies: ee-first "1.1.1" +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -1583,6 +2077,22 @@ once@^1.3.0: dependencies: wrappy "1" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@^8.0.9: + version "8.4.0" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" + integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -1611,6 +2121,14 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" +p-retry@^4.5.0: + version "4.6.2" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" + integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== + dependencies: + "@types/retry" "0.12.0" + retry "^0.13.1" + p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -1621,7 +2139,7 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== -parseurl@~1.3.3: +parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== @@ -1636,7 +2154,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== @@ -1646,6 +2164,11 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -1718,6 +2241,19 @@ postcss@^8.4.7: picocolors "^1.0.0" source-map-js "^1.0.2" +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" @@ -1742,7 +2278,7 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" -range-parser@^1.2.1: +range-parser@^1.2.1, range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== @@ -1757,6 +2293,28 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" +readable-stream@^2.0.1: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -1793,6 +2351,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -1819,6 +2382,11 @@ resolve@^1.9.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +retry@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + rfdc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" @@ -1831,7 +2399,12 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" -safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2: +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -1850,6 +2423,28 @@ schema-utils@^3.1.0, schema-utils@^3.1.1: ajv "^6.12.5" ajv-keywords "^3.5.2" +schema-utils@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" + integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.8.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.0.0" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== + +selfsigned@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.0.1.tgz#8b2df7fa56bf014d19b6007655fff209c0ef0a56" + integrity sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ== + dependencies: + node-forge "^1" + semver@^7.3.5: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" @@ -1857,6 +2452,25 @@ semver@^7.3.5: dependencies: lru-cache "^6.0.0" +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + serialize-javascript@6.0.0, serialize-javascript@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" @@ -1864,6 +2478,34 @@ serialize-javascript@6.0.0, serialize-javascript@^6.0.0: dependencies: randombytes "^2.1.0" +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw== + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + setprototypeof@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" @@ -1897,6 +2539,11 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + snabbdom@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/snabbdom/-/snabbdom-3.5.0.tgz#e75acbdedb26ea327c75028a433ba064db0ccf6e" @@ -1928,6 +2575,15 @@ socket.io@^4.4.1: socket.io-adapter "~2.4.0" socket.io-parser "~4.0.4" +sockjs@^0.3.24: + version "0.3.24" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" + integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== + dependencies: + faye-websocket "^0.11.3" + uuid "^8.3.2" + websocket-driver "^0.7.4" + source-map-js@^1.0.1, source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" @@ -1960,6 +2616,29 @@ source-map@~0.7.2: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + split.js@^1.6.5: version "1.6.5" resolved "https://registry.yarnpkg.com/split.js/-/split.js-1.6.5.tgz#f7f61da1044c9984cb42947df4de4fadb5a3f300" @@ -1970,7 +2649,7 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== -statuses@~1.5.0: +"statuses@>= 1.4.0 < 2", statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= @@ -1993,6 +2672,20 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -2005,6 +2698,11 @@ strip-comments@^2.0.1: resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-2.0.1.tgz#4ad11c3fbcac177a67a40ac224ca339ca1c1ba9b" integrity sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw== +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-json-comments@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -2067,6 +2765,11 @@ terser@^5.7.2: source-map "~0.7.2" source-map-support "~0.5.20" +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + tmp@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" @@ -2131,7 +2834,7 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -util-deprecate@^1.0.2: +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= @@ -2141,7 +2844,12 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -vary@^1: +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= @@ -2164,6 +2872,13 @@ watchpack@^2.3.1: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + webpack-cli@4.10.0: version "4.10.0" resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31" @@ -2182,6 +2897,52 @@ webpack-cli@4.10.0: rechoir "^0.7.0" webpack-merge "^5.7.3" +webpack-dev-middleware@^5.3.1: + version "5.3.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f" + integrity sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA== + dependencies: + colorette "^2.0.10" + memfs "^3.4.3" + mime-types "^2.1.31" + range-parser "^1.2.1" + schema-utils "^4.0.0" + +webpack-dev-server@4.9.2: + version "4.9.2" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.9.2.tgz#c188db28c7bff12f87deda2a5595679ebbc3c9bc" + integrity sha512-H95Ns95dP24ZsEzO6G9iT+PNw4Q7ltll1GfJHV4fKphuHWgKFzGHWi4alTlTnpk1SPPk41X+l2RB7rLfIhnB9Q== + dependencies: + "@types/bonjour" "^3.5.9" + "@types/connect-history-api-fallback" "^1.3.5" + "@types/express" "^4.17.13" + "@types/serve-index" "^1.9.1" + "@types/serve-static" "^1.13.10" + "@types/sockjs" "^0.3.33" + "@types/ws" "^8.5.1" + ansi-html-community "^0.0.8" + bonjour-service "^1.0.11" + chokidar "^3.5.3" + colorette "^2.0.10" + compression "^1.7.4" + connect-history-api-fallback "^1.6.0" + default-gateway "^6.0.3" + express "^4.17.3" + graceful-fs "^4.2.6" + html-entities "^2.3.2" + http-proxy-middleware "^2.0.3" + ipaddr.js "^2.0.1" + open "^8.0.9" + p-retry "^4.5.0" + rimraf "^3.0.2" + schema-utils "^4.0.0" + selfsigned "^2.0.1" + serve-index "^1.9.1" + sockjs "^0.3.24" + spdy "^4.0.2" + webpack-dev-middleware "^5.3.1" + ws "^8.4.2" + webpack-merge@^4.1.5: version "4.2.2" resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" @@ -2232,6 +2993,20 @@ webpack@5.73.0: watchpack "^2.3.1" webpack-sources "^3.2.3" +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + which@^1.2.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -2270,6 +3045,11 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +ws@^8.4.2: + version "8.8.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.0.tgz#8e71c75e2f6348dbf8d78005107297056cb77769" + integrity sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ== + ws@~8.2.3: version "8.2.3" resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fab0a54..10449f7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -153,7 +153,7 @@ ktorServer-defaultHeaders = { group = "io.ktor", name = "ktor-server-defaul ktorServer-forwardedHeader = { group = "io.ktor", name = "ktor-server-forwarded-header" } ktorServer-hsts = { group = "io.ktor", name = "ktor-server-hsts" } ktorServer-httpRedirect = { group = "io.ktor", name = "ktor-server-http-redirect" } -#ktorServer-netty = { group = "io.ktor", name = "ktor-server-netty" } +ktorServer-netty = { group = "io.ktor", name = "ktor-server-netty" } ktorServer-cio = { group = "io.ktor", name = "ktor-server-cio" } ktorServer-partialContent = { group = "io.ktor", name = "ktor-server-partial-content" } ktorServer-resources = { group = "io.ktor", name = "ktor-server-resources" } diff --git a/modules/events-schema/build.gradle.kts b/modules/events-library/build.gradle.kts similarity index 93% rename from modules/events-schema/build.gradle.kts rename to modules/events-library/build.gradle.kts index 161fa87..e7ac840 100644 --- a/modules/events-schema/build.gradle.kts +++ b/modules/events-library/build.gradle.kts @@ -51,6 +51,12 @@ kotlin { implementation(libs.kotlinx.serialization.core) implementation(libs.kotlinx.serialization.json) api("dev.adamko.kxstsgen:kxs-ts-gen-core:0.1.3") + + implementation(dependencies.platform(libs.okio.bom)) + implementation(libs.okio.core) + + implementation(dependencies.platform(libs.kotlinx.coroutines.bom)) + implementation(libs.kotlinx.coroutines.core) } } diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/json.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/library/json.kt similarity index 98% rename from modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/json.kt rename to modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/library/json.kt index ea57da1..ee63cc1 100644 --- a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/json.kt +++ b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/library/json.kt @@ -1,4 +1,4 @@ -package dev.adamko.kafkatorio.schema +package dev.adamko.kafkatorio.library import kotlin.reflect.KClass import kotlinx.serialization.DeserializationStrategy @@ -24,7 +24,6 @@ val jsonMapperKafkatorio = Json { serializersModule = SerializersModule { contextual(List::class) { args -> FactorioJsonListSerializer(args[0]) } } - } diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/serdes/kxsBinary.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/library/kxsBinary.kt similarity index 99% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/serdes/kxsBinary.kt rename to modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/library/kxsBinary.kt index f474a85..723e2bc 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/serdes/kxsBinary.kt +++ b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/library/kxsBinary.kt @@ -1,4 +1,4 @@ -package dev.adamko.kafkatorio.processor.serdes +package dev.adamko.kafkatorio.library import kotlinx.serialization.BinaryFormat import kotlinx.serialization.DeserializationStrategy diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/colours.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/colours.kt similarity index 100% rename from modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/colours.kt rename to modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/colours.kt diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioIds.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioIds.kt similarity index 100% rename from modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioIds.kt rename to modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioIds.kt diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioPrototypes.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioPrototypes.kt similarity index 100% rename from modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioPrototypes.kt rename to modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioPrototypes.kt diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/mapTile.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/mapTile.kt similarity index 100% rename from modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/mapTile.kt rename to modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/mapTile.kt diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/positions.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/positions.kt similarity index 100% rename from modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/positions.kt rename to modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/positions.kt diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/resources.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/resources.kt similarity index 100% rename from modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/resources.kt rename to modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/resources.kt diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/eventServerPacket.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/eventServerPacket.kt similarity index 100% rename from modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/eventServerPacket.kt rename to modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/eventServerPacket.kt diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacket.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacket.kt similarity index 100% rename from modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacket.kt rename to modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacket.kt diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacketInstant.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacketInstant.kt similarity index 100% rename from modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacketInstant.kt rename to modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacketInstant.kt diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacketKeyed.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacketKeyed.kt similarity index 100% rename from modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacketKeyed.kt rename to modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacketKeyed.kt diff --git a/modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/ColourHexTest.kt b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/ColourHexTest.kt similarity index 97% rename from modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/ColourHexTest.kt rename to modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/ColourHexTest.kt index 935ca93..3279283 100644 --- a/modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/ColourHexTest.kt +++ b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/ColourHexTest.kt @@ -1,10 +1,10 @@ package dev.adamko.kafkatorio.events.schema +import dev.adamko.kafkatorio.library.jsonMapperKafkatorio import dev.adamko.kafkatorio.schema.common.Colour import dev.adamko.kafkatorio.schema.common.ColourHex import dev.adamko.kafkatorio.schema.common.toHex import dev.adamko.kafkatorio.schema.common.toPercentile -import dev.adamko.kafkatorio.schema.jsonMapperKafkatorio import io.kotest.assertions.withClue import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.floats.shouldBeWithinPercentageOf @@ -13,6 +13,7 @@ import io.kotest.matchers.shouldBe import io.kotest.property.checkAll import kotlinx.serialization.decodeFromString + class ColourHexTest : BehaviorSpec({ Given("colour json") { diff --git a/modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/MapChunkUpdateTest.kt b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/MapChunkUpdateTest.kt similarity index 100% rename from modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/MapChunkUpdateTest.kt rename to modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/MapChunkUpdateTest.kt diff --git a/modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/PrototypesTest.kt b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/PrototypesTest.kt similarity index 100% rename from modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/PrototypesTest.kt rename to modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/PrototypesTest.kt diff --git a/modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/UpdatePacketsTest.kt b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/UpdatePacketsTest.kt similarity index 100% rename from modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/UpdatePacketsTest.kt rename to modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/UpdatePacketsTest.kt diff --git a/modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapChunkPositionBoundsTest.kt b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapChunkPositionBoundsTest.kt similarity index 100% rename from modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapChunkPositionBoundsTest.kt rename to modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapChunkPositionBoundsTest.kt diff --git a/modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapChunkPositionTest.kt b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapChunkPositionTest.kt similarity index 100% rename from modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapChunkPositionTest.kt rename to modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapChunkPositionTest.kt diff --git a/modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTileDictionaryTest.kt b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTileDictionaryTest.kt similarity index 100% rename from modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTileDictionaryTest.kt rename to modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTileDictionaryTest.kt diff --git a/modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTilePositionTest.kt b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTilePositionTest.kt similarity index 100% rename from modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTilePositionTest.kt rename to modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTilePositionTest.kt diff --git a/modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/packets/EntityUpdateTest.kt b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/packets/EntityUpdateTest.kt similarity index 100% rename from modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/packets/EntityUpdateTest.kt rename to modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/packets/EntityUpdateTest.kt diff --git a/modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/ValueClassTransformer.kt b/modules/events-library/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/ValueClassTransformer.kt similarity index 100% rename from modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/ValueClassTransformer.kt rename to modules/events-library/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/ValueClassTransformer.kt diff --git a/modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts.kt b/modules/events-library/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts.kt similarity index 100% rename from modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts.kt rename to modules/events-library/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts.kt diff --git a/modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts2.kt b/modules/events-library/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts2.kt similarity index 100% rename from modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts2.kt rename to modules/events-library/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts2.kt diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/misc/FileEventsFlow.kt b/modules/events-library/src/jvmMain/kotlin/dev/adamko/kafkatorio/library/FileEventsFlow.kt similarity index 100% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/misc/FileEventsFlow.kt rename to modules/events-library/src/jvmMain/kotlin/dev/adamko/kafkatorio/library/FileEventsFlow.kt diff --git a/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/misc/KxsBinaryTests.kt b/modules/events-library/src/jvmTest/kotlin/dev/adamko/kafkatorio/library/KxsBinaryTests.kt similarity index 97% rename from modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/misc/KxsBinaryTests.kt rename to modules/events-library/src/jvmTest/kotlin/dev/adamko/kafkatorio/library/KxsBinaryTests.kt index eb6702c..541f243 100644 --- a/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/misc/KxsBinaryTests.kt +++ b/modules/events-library/src/jvmTest/kotlin/dev/adamko/kafkatorio/library/KxsBinaryTests.kt @@ -1,15 +1,12 @@ -package dev.adamko.kafkatorio.processor.misc +package dev.adamko.kafkatorio.library -import dev.adamko.kafkatorio.processor.serdes.kxsBinary import dev.adamko.kafkatorio.schema.common.ServerMapChunkId -import dev.adamko.kafkatorio.processor.topology.ServerMapChunkTiles import dev.adamko.kafkatorio.schema.common.ChunkSize import dev.adamko.kafkatorio.schema.common.ColourHex import dev.adamko.kafkatorio.schema.common.FactorioServerId import dev.adamko.kafkatorio.schema.common.MapChunkPosition import dev.adamko.kafkatorio.schema.common.MapTilePosition import dev.adamko.kafkatorio.schema.common.SurfaceIndex -import dev.adamko.kafkatorio.schema.jsonMapperKafkatorio import io.kotest.assertions.withClue import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.collections.shouldContainExactly @@ -42,6 +39,7 @@ import io.kotest.property.arbitrary.uInt import io.kotest.property.arbitrary.uLong import io.kotest.property.arbitrary.uShort import io.kotest.property.checkAll +import kotlinx.serialization.Serializable import kotlinx.serialization.builtins.serializer import kotlinx.serialization.decodeFromByteArray import kotlinx.serialization.decodeFromString @@ -316,4 +314,15 @@ class KxsBinaryTests : FunSpec({ } } } -}) +}) { + + @Serializable + data class ServerMapChunkTiles( + val chunkId: ServerMapChunkId, + val map: Map, + ) { + operator fun plus(other: ServerMapChunkTiles) = copy(map = map + other.map) + } + + +} diff --git a/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/serdes/MapTileDictionaryTest.kt b/modules/events-library/src/jvmTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTileDictionaryTest.kt similarity index 89% rename from modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/serdes/MapTileDictionaryTest.kt rename to modules/events-library/src/jvmTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTileDictionaryTest.kt index 31addee..fdf6545 100644 --- a/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/serdes/MapTileDictionaryTest.kt +++ b/modules/events-library/src/jvmTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTileDictionaryTest.kt @@ -1,7 +1,6 @@ -package dev.adamko.kafkatorio.processor.serdes +package dev.adamko.kafkatorio.schema.common -import dev.adamko.kafkatorio.schema.common.MapTileDictionary -import dev.adamko.kafkatorio.schema.common.PrototypeName +import dev.adamko.kafkatorio.library.kxsBinary import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.equality.shouldBeEqualToComparingFields import kotlinx.serialization.decodeFromByteArray diff --git a/modules/events-mod/build.gradle.kts b/modules/events-mod/build.gradle.kts index bbfb92e..59dc28b 100644 --- a/modules/events-mod/build.gradle.kts +++ b/modules/events-mod/build.gradle.kts @@ -63,7 +63,7 @@ val typescriptEventsSchema: Configuration by configurations.creating { dependencies { - typescriptEventsSchema(projects.modules.eventsSchema) + typescriptEventsSchema(projects.modules.eventsLibrary) } diff --git a/modules/events-processor/build.gradle.kts b/modules/events-processor/build.gradle.kts deleted file mode 100644 index 6ccc2d3..0000000 --- a/modules/events-processor/build.gradle.kts +++ /dev/null @@ -1,125 +0,0 @@ -import dev.adamko.kafkatorio.task.KafkaConsumerGroupsTask -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - - -plugins { - dev.adamko.kafkatorio.lang.`kotlin-jvm` - kotlin("plugin.serialization") - application -} - - -description = """ - Receive raw Factorio Events from Kafka and process them into targeted topics or data formats. - - Factorio events -> Mod -> Kafka -> ***Factorio Events Processor*** -> processed events - """.trimIndent() - -val projectId: String by project.extra - -val kafkaStateDir: Directory = layout.projectDirectory.dir("kafka-state") - - -dependencies { - implementation(platform(projects.modules.versionsPlatform)) - - implementation(libs.kafka.streams) - testImplementation(libs.kafka.streamsTestUtils) - - implementation(projects.modules.eventsSchema) - -// implementation("com.ionspin.kotlin:bignum:0.3.3") - - implementation(libs.kotlinx.serialization.core) - implementation(libs.kotlinx.serialization.json) -// implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf") - - implementation(libs.kotlinx.coroutines.core) - - implementation(libs.bundles.http4k) - implementation(libs.http4k.format.kotlinx) - - - implementation(libs.bundles.logging) - - implementation(libs.scrimage.core) - - implementation(libs.okio.core) - - - // - implementation(libs.ktorSerialization.kotlinxJson) - - with(libs.ktorServer) { - implementation(core) - implementation(callId) - implementation(callLogging) - implementation(contentNegotiaion) - implementation(cio) -// implementation(netty) - implementation(autoHeadResponse) - implementation(partialContent) - implementation(resources) - implementation(statusPages) - implementation(websockets) - implementation(compression) - } - - with(libs.ktorNetwork) { - implementation(core) - implementation(tls) - } - - // - - - implementation(libs.simpleSyslogParser) - - implementation(libs.kafka.kotkaStreams) { - isChanging = false - } - - implementation(libs.bundles.hoplite) -} - - -application { - mainClass.set("dev.adamko.kafkatorio.processor.EventProcessorKt") - -// applicationDefaultJvmArgs += listOf( -// "-Dcom.sun.management.jmxremote.port=9186", -// "-Dcom.sun.management.jmxremote.rmi.port=9186", -// "-Dcom.sun.management.jmxremote.ssl=false", -// "-Dcom.sun.management.jmxremote.local.only=false", -// "-Dcom.sun.management.jmxremote.authenticate=false", -// ) -} - -tasks.withType().configureEach { - kotlinOptions.freeCompilerArgs += listOf( - "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", - "-opt-in=kotlinx.coroutines.FlowPreview", - "-opt-in=kotlinx.serialization.ExperimentalSerializationApi", - ) -} - - -val kafkaStateDirDelete by tasks.registering(Delete::class) { - group = project.name - mustRunAfter(kafkaConsumersDelete) - delete(kafkaStateDir) -} - -val kafkaConsumersDelete by tasks.registering(KafkaConsumerGroupsTask.DeleteAll::class) { - group = project.name -} - -//tasks.run.configure { -// dependsOn(kafkatorioEventsServerKafkaForceReset) -//} - -idea { - module { - excludeDirs = excludeDirs + kafkaStateDir.asFile - } -} diff --git a/modules/events-server/.gitignore b/modules/events-server/.gitignore index fe98be7..09eceef 100644 --- a/modules/events-server/.gitignore +++ b/modules/events-server/.gitignore @@ -1,2 +1,2 @@ kafka-state/ -kafkatorio-tiles/ +server-data/ diff --git a/modules/events-server/build.gradle.kts b/modules/events-server/build.gradle.kts index 5cf21e9..769882a 100644 --- a/modules/events-server/build.gradle.kts +++ b/modules/events-server/build.gradle.kts @@ -1,5 +1,6 @@ import dev.adamko.kafkatorio.task.KafkaConsumerGroupsTask import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.utils.addToStdlib.applyIf plugins { @@ -22,9 +23,7 @@ dependencies { implementation(libs.kafka.streams) testImplementation(libs.kafka.streamsTestUtils) - implementation(projects.modules.eventsSchema) - -// implementation("com.ionspin.kotlin:bignum:0.3.3") + implementation(projects.modules.eventsLibrary) implementation(libs.kotlinx.serialization.core) implementation(libs.kotlinx.serialization.json) @@ -32,17 +31,12 @@ dependencies { implementation(libs.kotlinx.coroutines.core) - implementation(libs.bundles.http4k) - implementation(libs.http4k.format.kotlinx) - - implementation(libs.bundles.logging) implementation(libs.scrimage.core) implementation(libs.okio.core) - // implementation(libs.ktorSerialization.kotlinxJson) @@ -81,15 +75,7 @@ dependencies { application { // mainClass.set("dev.adamko.kafkatorio.processor.EventProcessorKt") - mainClass.set("dev.adamko.kafkatorio.server.KafkatorioEventsServerKt") - -// applicationDefaultJvmArgs += listOf( -// "-Dcom.sun.management.jmxremote.port=9186", -// "-Dcom.sun.management.jmxremote.rmi.port=9186", -// "-Dcom.sun.management.jmxremote.ssl=false", -// "-Dcom.sun.management.jmxremote.local.only=false", -// "-Dcom.sun.management.jmxremote.authenticate=false", -// ) + mainClass.set("dev.adamko.kafkatorio.server.EventsServerKt") } tasks.withType().configureEach { @@ -111,9 +97,6 @@ val kafkaConsumersDelete by tasks.registering(KafkaConsumerGroupsTask.DeleteAll: group = project.name } -//tasks.run.configure { -// dependsOn(kafkatorioEventsServerKafkaForceReset) -//} idea { module { diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/eventProcessor.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/eventProcessor.kt deleted file mode 100644 index ae1e860..0000000 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/eventProcessor.kt +++ /dev/null @@ -1,58 +0,0 @@ -package dev.adamko.kafkatorio.processor - - -import dev.adamko.kafkatorio.processor.admin.KafkatorioKafkaAdmin -import dev.adamko.kafkatorio.processor.config.ApplicationProperties -import dev.adamko.kafkatorio.processor.tileserver.SyslogSocketServer -import dev.adamko.kafkatorio.processor.tileserver.WebMapTileServer -import dev.adamko.kafkatorio.processor.tileserver.WebsocketServer -import dev.adamko.kafkatorio.processor.tileserver.webServer -import kotlinx.coroutines.awaitCancellation -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.currentCoroutineContext -import kotlinx.coroutines.job -import kotlinx.coroutines.launch -import org.http4k.server.Http4kServer - - -suspend fun main() { - - val appProps = ApplicationProperties.load() - - val admin = KafkatorioKafkaAdmin(appProps) - admin.createKafkatorioTopics() - - - val syslogServer = SyslogSocketServer(appProps) - val wsServer = WebsocketServer() - val tileServer = WebMapTileServer(appProps) - val topology = KafkatorioTopology(appProps, wsServer, syslogServer) - - coroutineScope { - launch { - syslogServer.start() - } - - launch { - topology.start() - - println("launched KafkatorioTopology") - - awaitCancellation() - } - - launch { - val webServer: Http4kServer = webServer(tileServer, wsServer, appProps) - - currentCoroutineContext().job.invokeOnCompletion { - println("webserver stopping. Cause: $it") - webServer.stop() - } - - webServer.start() - println("launched webserver port:${webServer.port()}") - - awaitCancellation() - } - } -} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/SyslogSocketServer.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/SyslogSocketServer.kt index 4a1da1c..3c4a87a 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/SyslogSocketServer.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/SyslogSocketServer.kt @@ -1,168 +1,168 @@ package dev.adamko.kafkatorio.processor.tileserver -import com.github.palindromicity.syslog.AllowableDeviations -import com.github.palindromicity.syslog.SyslogParser -import com.github.palindromicity.syslog.SyslogParserBuilder -import com.github.palindromicity.syslog.SyslogSpecification -import com.github.palindromicity.syslog.dsl.SyslogFieldKeys -import dev.adamko.kafkatorio.processor.config.ApplicationProperties -import dev.adamko.kafkatorio.processor.tileserver.SyslogMsg.Companion.toSyslogMsg -import io.ktor.network.selector.SelectorManager -import io.ktor.network.sockets.aSocket -import io.ktor.network.sockets.awaitClosed -import io.ktor.network.sockets.openReadChannel -import io.ktor.utils.io.readUTF8Line -import java.util.EnumSet -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.asSharedFlow -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch -import kotlinx.coroutines.yield - - -class SyslogSocketServer( - appProps: ApplicationProperties, - dispatcher: CoroutineDispatcher = Dispatchers.IO, -) { - - private val selectorManager: SelectorManager = SelectorManager(dispatcher) - - - private val serverSocketTcp = aSocket(selectorManager) - .tcp() - .bind( - appProps.socketServerHost, - appProps.socketServerPort, - ) - - -// private val serverSocketUdp: BoundDatagramSocket = aSocket(selectorManager) -// .udp() -// .bind( -// localAddress = InetSocketAddress( -// appProps.socketServerHost, -// appProps.socketServerPortUdp, -// ), -// ) - - - private val syslogParser: SyslogParser = SyslogParserBuilder() - .withDeviations(EnumSet.of(AllowableDeviations.PRIORITY, AllowableDeviations.VERSION)) - .forSpecification(SyslogSpecification.RFC_5424) - .build() - - - private val _messages: MutableSharedFlow = MutableSharedFlow() - val messages: SharedFlow - get() = _messages.asSharedFlow() - - - suspend fun start() { -// udp() - tcp() - } - -// private suspend fun udp() { -// println("[SyslogSocketServer] started listening: ${serverSocketUdp.localAddress}") +//import com.github.palindromicity.syslog.AllowableDeviations +//import com.github.palindromicity.syslog.SyslogParser +//import com.github.palindromicity.syslog.SyslogParserBuilder +//import com.github.palindromicity.syslog.SyslogSpecification +//import com.github.palindromicity.syslog.dsl.SyslogFieldKeys +//import dev.adamko.kafkatorio.server.config.ApplicationProperties +//import dev.adamko.kafkatorio.processor.tileserver.SyslogMsg.Companion.toSyslogMsg +//import io.ktor.network.selector.SelectorManager +//import io.ktor.network.sockets.aSocket +//import io.ktor.network.sockets.awaitClosed +//import io.ktor.network.sockets.openReadChannel +//import io.ktor.utils.io.readUTF8Line +//import java.util.EnumSet +//import kotlinx.coroutines.CoroutineDispatcher +//import kotlinx.coroutines.Dispatchers +//import kotlinx.coroutines.coroutineScope +//import kotlinx.coroutines.flow.MutableSharedFlow +//import kotlinx.coroutines.flow.SharedFlow +//import kotlinx.coroutines.flow.asSharedFlow +//import kotlinx.coroutines.isActive +//import kotlinx.coroutines.launch +//import kotlinx.coroutines.yield // -// serverSocketUdp.incoming -// .receiveAsFlow() -// .map {udpPacket: Datagram -> -// val msg = udpPacket.packet.readText() -// println("[SyslogSocketServer] received msg: $msg") -// syslogParser.parseLine(msg).toSyslogMsg() -// }.collect(_messages) +// +//class SyslogSocketServer( +// appProps: ApplicationProperties, +// dispatcher: CoroutineDispatcher = Dispatchers.IO, +//) { +// +// private val selectorManager: SelectorManager = SelectorManager(dispatcher) +// +// +// private val serverSocketTcp = aSocket(selectorManager) +// .tcp() +// .bind( +// appProps.socketServerHost, +// appProps.socketServerPort, +// ) +// +// +//// private val serverSocketUdp: BoundDatagramSocket = aSocket(selectorManager) +//// .udp() +//// .bind( +//// localAddress = InetSocketAddress( +//// appProps.socketServerHost, +//// appProps.socketServerPortUdp, +//// ), +//// ) +// +// +// private val syslogParser: SyslogParser = SyslogParserBuilder() +// .withDeviations(EnumSet.of(AllowableDeviations.PRIORITY, AllowableDeviations.VERSION)) +// .forSpecification(SyslogSpecification.RFC_5424) +// .build() +// +// +// private val _messages: MutableSharedFlow = MutableSharedFlow() +// val messages: SharedFlow +// get() = _messages.asSharedFlow() +// +// +// suspend fun start() { +//// udp() +// tcp() // } - - private suspend fun tcp() = coroutineScope { - println("[SyslogSocketServer] started listening: ${serverSocketTcp.localAddress}") - - while (isActive) { - val socket = serverSocketTcp.accept() - - launch { - val channel = socket.openReadChannel() - try { - while (socket.socketContext.isActive) { - val line = channel.readUTF8Line() - println("[SyslogSocketServer] received: $line") - - val syslog = syslogParser.parseLine(line).toSyslogMsg() - - _messages.emit(syslog) - - yield() - } - } catch (e: Exception) { - socket.awaitClosed() - } - } - } - - yield() - } -} - - -data class SyslogMsg( - val src: Map -) { - - val message: String? - get() = src[SyslogFieldKeys.MESSAGE.field] - - val headerAppName: String? - get() = src[SyslogFieldKeys.HEADER_APPNAME.field] - - val headerHostName: String? - get() = src[SyslogFieldKeys.HEADER_HOSTNAME.field] - - val headerPri: String? - get() = src[SyslogFieldKeys.HEADER_PRI.field] - - val headerPriSeverity: String? - get() = src[SyslogFieldKeys.HEADER_PRI_SEVERITY.field] - - val headerPriFacility: String? - get() = src[SyslogFieldKeys.HEADER_PRI_FACILITY.field] - - val headerProcId: String? - get() = src[SyslogFieldKeys.HEADER_PROCID.field] - - val headerTimestamp: String? - get() = src[SyslogFieldKeys.HEADER_TIMESTAMP.field] - - val headerMsgId: String? - get() = src[SyslogFieldKeys.HEADER_MSGID.field] - - val headerVersion: String? - get() = src[SyslogFieldKeys.HEADER_VERSION.field] - - val structuredBase: String? - get() = src[SyslogFieldKeys.STRUCTURED_BASE.field] - - val structuredElementIdFmt: String? - get() = src[SyslogFieldKeys.STRUCTURED_ELEMENT_ID_FMT.field] - - val structuredElementIdPnameFmt: String? - get() = src[SyslogFieldKeys.STRUCTURED_ELEMENT_ID_PNAME_FMT.field] - - val structuredElementIdPnamePattern: String? - get() = src[SyslogFieldKeys.STRUCTURED_ELEMENT_ID_PNAME_PATTERN.field] - - companion object { - fun Map.toSyslogMsg(): SyslogMsg { - val map = entries.mapNotNull { (k, v) -> - when (v) { - is String -> k to v - else -> null - } - }.toMap() - return SyslogMsg(map) - } - } -} +// +//// private suspend fun udp() { +//// println("[SyslogSocketServer] started listening: ${serverSocketUdp.localAddress}") +//// +//// serverSocketUdp.incoming +//// .receiveAsFlow() +//// .map {udpPacket: Datagram -> +//// val msg = udpPacket.packet.readText() +//// println("[SyslogSocketServer] received msg: $msg") +//// syslogParser.parseLine(msg).toSyslogMsg() +//// }.collect(_messages) +//// } +// +// private suspend fun tcp() = coroutineScope { +// println("[SyslogSocketServer] started listening: ${serverSocketTcp.localAddress}") +// +// while (isActive) { +// val socket = serverSocketTcp.accept() +// +// launch { +// val channel = socket.openReadChannel() +// try { +// while (socket.socketContext.isActive) { +// val line = channel.readUTF8Line() +// println("[SyslogSocketServer] received: $line") +// +// val syslog = syslogParser.parseLine(line).toSyslogMsg() +// +// _messages.emit(syslog) +// +// yield() +// } +// } catch (e: Exception) { +// socket.awaitClosed() +// } +// } +// } +// +// yield() +// } +//} +// +// +//data class SyslogMsg( +// val src: Map +//) { +// +// val message: String? +// get() = src[SyslogFieldKeys.MESSAGE.field] +// +// val headerAppName: String? +// get() = src[SyslogFieldKeys.HEADER_APPNAME.field] +// +// val headerHostName: String? +// get() = src[SyslogFieldKeys.HEADER_HOSTNAME.field] +// +// val headerPri: String? +// get() = src[SyslogFieldKeys.HEADER_PRI.field] +// +// val headerPriSeverity: String? +// get() = src[SyslogFieldKeys.HEADER_PRI_SEVERITY.field] +// +// val headerPriFacility: String? +// get() = src[SyslogFieldKeys.HEADER_PRI_FACILITY.field] +// +// val headerProcId: String? +// get() = src[SyslogFieldKeys.HEADER_PROCID.field] +// +// val headerTimestamp: String? +// get() = src[SyslogFieldKeys.HEADER_TIMESTAMP.field] +// +// val headerMsgId: String? +// get() = src[SyslogFieldKeys.HEADER_MSGID.field] +// +// val headerVersion: String? +// get() = src[SyslogFieldKeys.HEADER_VERSION.field] +// +// val structuredBase: String? +// get() = src[SyslogFieldKeys.STRUCTURED_BASE.field] +// +// val structuredElementIdFmt: String? +// get() = src[SyslogFieldKeys.STRUCTURED_ELEMENT_ID_FMT.field] +// +// val structuredElementIdPnameFmt: String? +// get() = src[SyslogFieldKeys.STRUCTURED_ELEMENT_ID_PNAME_FMT.field] +// +// val structuredElementIdPnamePattern: String? +// get() = src[SyslogFieldKeys.STRUCTURED_ELEMENT_ID_PNAME_PATTERN.field] +// +// companion object { +// fun Map.toSyslogMsg(): SyslogMsg { +// val map = entries.mapNotNull { (k, v) -> +// when (v) { +// is String -> k to v +// else -> null +// } +// }.toMap() +// return SyslogMsg(map) +// } +// } +//} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/WebMapTileServer.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/WebMapTileServer.kt index e64335f..3f488e5 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/WebMapTileServer.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/WebMapTileServer.kt @@ -1,86 +1,86 @@ package dev.adamko.kafkatorio.processor.tileserver -import dev.adamko.kafkatorio.processor.config.ApplicationProperties -import java.security.MessageDigest -import org.http4k.core.Filter -import org.http4k.core.HttpHandler -import org.http4k.core.MemoryBody -import org.http4k.core.Method.GET -import org.http4k.core.Request -import org.http4k.core.Response -import org.http4k.core.Status -import org.http4k.core.then -import org.http4k.routing.ResourceLoader -import org.http4k.routing.RoutingHttpHandler -import org.http4k.routing.bind -import org.http4k.routing.routes -import org.http4k.routing.static - -internal class WebMapTileServer( - appProps: ApplicationProperties -) { - - private val tilesLoader = ResourceLoader.Directory(appProps.serverDataDir.toFile().canonicalPath) - - - private val filters = listOf( - ETagChecker(), - ).reduce(Filter::then) - - - private val routes: RoutingHttpHandler = routes( - "/tiles" bind GET to static(tilesLoader).withFilter(filters) - ) - - - fun build(): HttpHandler { - return routes - } - - - private class ETagChecker : Filter { - - override fun invoke(next: HttpHandler): HttpHandler = { request: Request -> - val requestedETag = request.header("If-None-Match") - - var response = next(request) - val responseBytes = response.body.stream.use { it.readAllBytes() } - val currentETag = responseBytes.md5() - - response = response.body(MemoryBody(responseBytes)) - - when { - currentETag == null -> { -// println("[${request.etagKey}] currentETag is null (requested: $requestedETag), executing request") - response - .header("Cache-Control", "no-cache, max-age=0, must-revalidate") - } - requestedETag == currentETag -> { -// println("[${request.etagKey}] currentETag == requested, returning 304 $requestedETag") - Response(Status.NOT_MODIFIED) - .header("Cache-Control", "no-cache, max-age=0, must-revalidate") - } - else -> { -// println("[${request.etagKey}] currentETag != requested, executing request and adding currentETag:$currentETag (requested:$requestedETag)") - response - .header("ETag", currentETag) -// .header("Cache-Control", "no-store") - .header("Cache-Control", "no-cache, max-age=0, must-revalidate") - } - } - } - } - - - companion object { - private fun ByteArray.md5(): String? { - return if (isEmpty()) { - null - } else { - MessageDigest.getInstance("MD5") - .digest(this) - .joinToString("") { "%02x".format(it) } - } - } - } -} +//import dev.adamko.kafkatorio.processor.config.ApplicationProperties +//import java.security.MessageDigest +//import org.http4k.core.Filter +//import org.http4k.core.HttpHandler +//import org.http4k.core.MemoryBody +//import org.http4k.core.Method.GET +//import org.http4k.core.Request +//import org.http4k.core.Response +//import org.http4k.core.Status +//import org.http4k.core.then +//import org.http4k.routing.ResourceLoader +//import org.http4k.routing.RoutingHttpHandler +//import org.http4k.routing.bind +//import org.http4k.routing.routes +//import org.http4k.routing.static +// +//internal class WebMapTileServer( +// appProps: ApplicationProperties +//) { +// +// private val tilesLoader = ResourceLoader.Directory(appProps.serverDataDir.toFile().canonicalPath) +// +// +// private val filters = listOf( +// ETagChecker(), +// ).reduce(Filter::then) +// +// +// private val routes: RoutingHttpHandler = routes( +// "/tiles" bind GET to static(tilesLoader).withFilter(filters) +// ) +// +// +// fun build(): HttpHandler { +// return routes +// } +// +// +// private class ETagChecker : Filter { +// +// override fun invoke(next: HttpHandler): HttpHandler = { request: Request -> +// val requestedETag = request.header("If-None-Match") +// +// var response = next(request) +// val responseBytes = response.body.stream.use { it.readAllBytes() } +// val currentETag = responseBytes.md5() +// +// response = response.body(MemoryBody(responseBytes)) +// +// when { +// currentETag == null -> { +//// println("[${request.etagKey}] currentETag is null (requested: $requestedETag), executing request") +// response +// .header("Cache-Control", "no-cache, max-age=0, must-revalidate") +// } +// requestedETag == currentETag -> { +//// println("[${request.etagKey}] currentETag == requested, returning 304 $requestedETag") +// Response(Status.NOT_MODIFIED) +// .header("Cache-Control", "no-cache, max-age=0, must-revalidate") +// } +// else -> { +//// println("[${request.etagKey}] currentETag != requested, executing request and adding currentETag:$currentETag (requested:$requestedETag)") +// response +// .header("ETag", currentETag) +//// .header("Cache-Control", "no-store") +// .header("Cache-Control", "no-cache, max-age=0, must-revalidate") +// } +// } +// } +// } +// +// +// companion object { +// private fun ByteArray.md5(): String? { +// return if (isEmpty()) { +// null +// } else { +// MessageDigest.getInstance("MD5") +// .digest(this) +// .joinToString("") { "%02x".format(it) } +// } +// } +// } +//} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/WebServer.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/WebServer.kt index 8533849..d72dc27 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/WebServer.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/WebServer.kt @@ -1,16 +1,16 @@ package dev.adamko.kafkatorio.processor.tileserver - -import dev.adamko.kafkatorio.processor.config.ApplicationProperties -import org.http4k.server.Http4kServer -import org.http4k.server.PolyHandler -import org.http4k.server.Undertow -import org.http4k.server.asServer - -internal fun webServer( - tileServer: WebMapTileServer, - wsServer: WebsocketServer, - appProps: ApplicationProperties, -): Http4kServer = PolyHandler( - tileServer.build(), - wsServer.build(), -).asServer(Undertow(appProps.webPort())) +// +//import dev.adamko.kafkatorio.processor.config.ApplicationProperties +//import org.http4k.server.Http4kServer +//import org.http4k.server.PolyHandler +//import org.http4k.server.Undertow +//import org.http4k.server.asServer +// +//internal fun webServer( +// tileServer: WebMapTileServer, +// wsServer: WebsocketServer, +// appProps: ApplicationProperties, +//): Http4kServer = PolyHandler( +// tileServer.build(), +// wsServer.build(), +//).asServer(Undertow(appProps.webPort())) diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/WebsocketServer.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/WebsocketServer.kt index d1ab9b6..dcf7bd3 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/WebsocketServer.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/tileserver/WebsocketServer.kt @@ -1,141 +1,141 @@ package dev.adamko.kafkatorio.processor.tileserver - -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException -import kotlin.time.Duration.Companion.seconds -import kotlin.time.TimeSource -import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.CoroutineName -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.channels.BufferOverflow -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.withIndex -import kotlinx.coroutines.isActive -import kotlinx.coroutines.job -import kotlinx.coroutines.launch -import kotlinx.coroutines.supervisorScope -import kotlinx.coroutines.suspendCancellableCoroutine -import org.http4k.routing.bind -import org.http4k.routing.websockets -import org.http4k.websocket.Websocket -import org.http4k.websocket.WsHandler -import org.http4k.websocket.WsMessage -import org.http4k.websocket.WsStatus - - -class WebsocketServer { - - private val serverScope = CoroutineScope( - CoroutineName("WsServer") + - Dispatchers.IO + - SupervisorJob() + - CoroutineExceptionHandler { _, e -> - println("[ws.WsServer] handling exception ${e.message}") - } - ) - - - private val clients: MutableSharedFlow = MutableSharedFlow( - replay = 100, - extraBufferCapacity = 100, - BufferOverflow.DROP_OLDEST, - ) - - - private val messages: MutableSharedFlow = MutableSharedFlow( - replay = 100, - extraBufferCapacity = 100, - BufferOverflow.DROP_OLDEST, - ) - - - private fun bindClient(ws: Websocket) = serverScope.launch { - println("[ws.bindClient] ${ws.upgradeRequest.toMessage()}") - clients.emit(ws) - } - - - fun sendMessage(msg: String) = serverScope.launch { - println("[ws.sendMessage] $msg") - messages.emit(msg) - } - - - fun build(): WsHandler { - val startTime = TimeSource.Monotonic.markNow() - - serverScope.launch { - supervisorScope { - clients - .withIndex() - .onEach { (id, ws) -> - createClient(id, ws) - }.launchIn(serverScope) - } - } - - serverScope.launch { - while (isActive) { - delay(10.seconds) - sendMessage("elapsed ${startTime.elapsedNow()}") - } - } - - return websockets( - "/ws/foo" bind { ws: Websocket -> - serverScope.launch { bindClient(ws) } - } - ) - } - - - private fun createClient(id: Int, ws: Websocket) { - val clientJob = SupervisorJob(serverScope.coroutineContext.job) - - serverScope.launch(CoroutineName("ws-client-$id") + clientJob) { - launch { - suspendCancellableCoroutine { cont -> - println("[ws-client] entering suspendCancellableCoroutine") - - cont.invokeOnCancellation { e: Throwable? -> - launch { sendMessage("[ws-client.invokeOnCompletion] closing client ws ${e?.message}") } - when (e) { - null -> ws.close(WsStatus.NORMAL) - else -> ws.close(WsStatus.ABNORMAL_CLOSE) - } - } - - ws.onError { e: Throwable -> - launch { sendMessage("[ws-client.onError] client $id error [${e.message}]") } - if (!cont.isCompleted) { - cont.resumeWithException(e) - } - } - - ws.onClose { status: WsStatus -> - launch { sendMessage("[ws-client.onClose] client $id disconnected [${status}]") } - if (!cont.isCompleted) { - cont.resume(status) - } - } - - ws.onMessage { wsMsg -> - launch { sendMessage("$id says: ${wsMsg.bodyString()}") } - } - } - } - - println("[ws-client] $id listening to messages") - messages - .onEach { msg -> - println("[ws-client] sending message to $id") - ws.send(WsMessage(msg)) - }.launchIn(this) - } - } -} +// +//import kotlin.coroutines.resume +//import kotlin.coroutines.resumeWithException +//import kotlin.time.Duration.Companion.seconds +//import kotlin.time.TimeSource +//import kotlinx.coroutines.CoroutineExceptionHandler +//import kotlinx.coroutines.CoroutineName +//import kotlinx.coroutines.CoroutineScope +//import kotlinx.coroutines.Dispatchers +//import kotlinx.coroutines.SupervisorJob +//import kotlinx.coroutines.channels.BufferOverflow +//import kotlinx.coroutines.delay +//import kotlinx.coroutines.flow.MutableSharedFlow +//import kotlinx.coroutines.flow.launchIn +//import kotlinx.coroutines.flow.onEach +//import kotlinx.coroutines.flow.withIndex +//import kotlinx.coroutines.isActive +//import kotlinx.coroutines.job +//import kotlinx.coroutines.launch +//import kotlinx.coroutines.supervisorScope +//import kotlinx.coroutines.suspendCancellableCoroutine +//import org.http4k.routing.bind +//import org.http4k.routing.websockets +//import org.http4k.websocket.Websocket +//import org.http4k.websocket.WsHandler +//import org.http4k.websocket.WsMessage +//import org.http4k.websocket.WsStatus +// +// +//class WebsocketServer { +// +// private val serverScope = CoroutineScope( +// CoroutineName("WsServer") + +// Dispatchers.IO + +// SupervisorJob() + +// CoroutineExceptionHandler { _, e -> +// println("[ws.WsServer] handling exception ${e.message}") +// } +// ) +// +// +// private val clients: MutableSharedFlow = MutableSharedFlow( +// replay = 100, +// extraBufferCapacity = 100, +// BufferOverflow.DROP_OLDEST, +// ) +// +// +// private val messages: MutableSharedFlow = MutableSharedFlow( +// replay = 100, +// extraBufferCapacity = 100, +// BufferOverflow.DROP_OLDEST, +// ) +// +// +// private fun bindClient(ws: Websocket) = serverScope.launch { +// println("[ws.bindClient] ${ws.upgradeRequest.toMessage()}") +// clients.emit(ws) +// } +// +// +// fun sendMessage(msg: String) = serverScope.launch { +// println("[ws.sendMessage] $msg") +// messages.emit(msg) +// } +// +// +// fun build(): WsHandler { +// val startTime = TimeSource.Monotonic.markNow() +// +// serverScope.launch { +// supervisorScope { +// clients +// .withIndex() +// .onEach { (id, ws) -> +// createClient(id, ws) +// }.launchIn(serverScope) +// } +// } +// +// serverScope.launch { +// while (isActive) { +// delay(10.seconds) +// sendMessage("elapsed ${startTime.elapsedNow()}") +// } +// } +// +// return websockets( +// "/ws/foo" bind { ws: Websocket -> +// serverScope.launch { bindClient(ws) } +// } +// ) +// } +// +// +// private fun createClient(id: Int, ws: Websocket) { +// val clientJob = SupervisorJob(serverScope.coroutineContext.job) +// +// serverScope.launch(CoroutineName("ws-client-$id") + clientJob) { +// launch { +// suspendCancellableCoroutine { cont -> +// println("[ws-client] entering suspendCancellableCoroutine") +// +// cont.invokeOnCancellation { e: Throwable? -> +// launch { sendMessage("[ws-client.invokeOnCompletion] closing client ws ${e?.message}") } +// when (e) { +// null -> ws.close(WsStatus.NORMAL) +// else -> ws.close(WsStatus.ABNORMAL_CLOSE) +// } +// } +// +// ws.onError { e: Throwable -> +// launch { sendMessage("[ws-client.onError] client $id error [${e.message}]") } +// if (!cont.isCompleted) { +// cont.resumeWithException(e) +// } +// } +// +// ws.onClose { status: WsStatus -> +// launch { sendMessage("[ws-client.onClose] client $id disconnected [${status}]") } +// if (!cont.isCompleted) { +// cont.resume(status) +// } +// } +// +// ws.onMessage { wsMsg -> +// launch { sendMessage("$id says: ${wsMsg.bodyString()}") } +// } +// } +// } +// +// println("[ws-client] $id listening to messages") +// messages +// .onEach { msg -> +// println("[ws-client] sending message to $id") +// ws.send(WsMessage(msg)) +// }.launchIn(this) +// } +// } +//} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/config/ApplicationProperties.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/config/ApplicationProperties.kt similarity index 95% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/config/ApplicationProperties.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/config/ApplicationProperties.kt index 204c74a..1595320 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/config/ApplicationProperties.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/config/ApplicationProperties.kt @@ -1,4 +1,4 @@ -package dev.adamko.kafkatorio.processor.config +package dev.adamko.kafkatorio.server.config import com.sksamuel.hoplite.ConfigLoaderBuilder import com.sksamuel.hoplite.addEnvironmentSource diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/config/PortVal.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/config/PortVal.kt similarity index 72% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/config/PortVal.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/config/PortVal.kt index e2f880d..a4c48c8 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/config/PortVal.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/config/PortVal.kt @@ -1,9 +1,7 @@ -package dev.adamko.kafkatorio.processor.config - -import org.http4k.cloudnative.env.Port +package dev.adamko.kafkatorio.server.config -/** Improved (slightly) version of http4k's [Port]. */ +/** Improved (slightly) version of http4k's `Port`. */ @JvmInline value class PortVal(val value: Int) { diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/serdes/kxsJson.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/config/kxsJson.kt similarity index 63% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/serdes/kxsJson.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/config/kxsJson.kt index e534e69..6dab1ed 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/serdes/kxsJson.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/config/kxsJson.kt @@ -1,8 +1,9 @@ -package dev.adamko.kafkatorio.processor.serdes +package dev.adamko.kafkatorio.server.config -import dev.adamko.kafkatorio.schema.jsonMapperKafkatorio +import dev.adamko.kafkatorio.library.jsonMapperKafkatorio import kotlinx.serialization.json.Json + val jsonMapper: Json = Json { prettyPrint = true prettyPrintIndent = " " diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/eventsServer.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/eventsServer.kt new file mode 100644 index 0000000..681afde --- /dev/null +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/eventsServer.kt @@ -0,0 +1,32 @@ +package dev.adamko.kafkatorio.server + +import dev.adamko.kafkatorio.server.config.ApplicationProperties +import dev.adamko.kafkatorio.server.socket.SyslogSocketServer +import dev.adamko.kafkatorio.server.web.startWebServer +import dev.adamko.kafkatorio.server.web.websocket.WebmapWebsocketServer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch + + +suspend fun main(): Unit = coroutineScope { + + val appProps = ApplicationProperties.load() + + val websocketServer = WebmapWebsocketServer() + val syslogSocketServer = SyslogSocketServer(appProps) + + launch { + startWebServer(appProps, websocketServer) + } + + + launch { + syslogSocketServer.start() + } + + +// launch(Dispatchers.Default.limitedParallelism(2)) { +// eventsProcessor(appProps, syslogSocketServer, websocketServer) +// } +} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/kafkatorioEventsServer.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/kafkatorioEventsServer.kt deleted file mode 100644 index a8cd36c..0000000 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/kafkatorioEventsServer.kt +++ /dev/null @@ -1,38 +0,0 @@ -package dev.adamko.kafkatorio.server - -import dev.adamko.kafkatorio.processor.config.ApplicationProperties -import io.ktor.http.HttpStatusCode -import io.ktor.server.application.Application -import io.ktor.server.application.install -import io.ktor.server.cio.CIO -import io.ktor.server.engine.embeddedServer -import io.ktor.server.plugins.callloging.CallLogging -import io.ktor.server.plugins.statuspages.StatusPages -import io.ktor.server.response.respondText - - -fun main() { - val appProps = ApplicationProperties.load() - - embeddedServer(CIO, port = appProps.webPort.value) { - - common() - - webmapWebsocketServer() - - webmapTileServer(appProps) - - syslogSocketServer(appProps) - - }.start(wait = true) -} - - -fun Application.common() { - install(StatusPages) { - exception { call, cause -> - call.respondText(text = "500: $cause", status = HttpStatusCode.InternalServerError) - } - } - install(CallLogging) -} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/misc/DebounceProcessor.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/DebounceProcessor.kt similarity index 98% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/misc/DebounceProcessor.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/DebounceProcessor.kt index 9502e63..de17abb 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/misc/DebounceProcessor.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/DebounceProcessor.kt @@ -1,4 +1,4 @@ -package dev.adamko.kafkatorio.processor.misc +package dev.adamko.kafkatorio.server.processor import dev.adamko.kotka.extensions.component1 import dev.adamko.kotka.extensions.component2 diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/KafkatorioTopology.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/KafkatorioTopology.kt similarity index 89% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/KafkatorioTopology.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/KafkatorioTopology.kt index 7df00b0..facbf6d 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/KafkatorioTopology.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/KafkatorioTopology.kt @@ -1,15 +1,12 @@ -package dev.adamko.kafkatorio.processor +package dev.adamko.kafkatorio.server.processor import com.github.palindromicity.syslog.dsl.SyslogFieldKeys -import dev.adamko.kafkatorio.processor.admin.TOPIC_SRC_SERVER_LOG -import dev.adamko.kafkatorio.processor.config.ApplicationProperties -import dev.adamko.kafkatorio.processor.tileserver.SyslogSocketServer -import dev.adamko.kafkatorio.processor.tileserver.WebsocketServer -import dev.adamko.kafkatorio.processor.topology.broadcastToWebsocket -import dev.adamko.kafkatorio.processor.topology.colourMapChunks -import dev.adamko.kafkatorio.processor.topology.factorioServerPacketStream -import dev.adamko.kafkatorio.processor.topology.saveMapTiles -import dev.adamko.kafkatorio.processor.topology.splitFactorioServerPacketStream +import dev.adamko.kafkatorio.server.config.ApplicationProperties +import dev.adamko.kafkatorio.server.processor.topology.colourMapChunks +import dev.adamko.kafkatorio.server.processor.topology.* +import dev.adamko.kafkatorio.server.socket.SyslogSocketServer +import dev.adamko.kafkatorio.server.web.websocket.WebmapWebsocketServer +import dev.adamko.kafkatorio.server.web.websocket.broadcastToWebsocket import java.util.Properties import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException @@ -40,7 +37,7 @@ import org.apache.kafka.streams.TopologyDescription internal class KafkatorioTopology( private val appProps: ApplicationProperties, - private val websocketServer: WebsocketServer, + private val wsServer: WebmapWebsocketServer, private val syslogServer: SyslogSocketServer, ) { @@ -86,7 +83,7 @@ internal class KafkatorioTopology( private suspend fun websocketBroadcaster() { val builder = StreamsBuilder() - broadcastToWebsocket(websocketServer, builder) + broadcastToWebsocket(wsServer, builder) val topology = builder.build() diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/StreamsExceptionHandler.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/StreamsExceptionHandler.kt similarity index 91% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/StreamsExceptionHandler.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/StreamsExceptionHandler.kt index a80dd72..03f0cc3 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/StreamsExceptionHandler.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/StreamsExceptionHandler.kt @@ -1,4 +1,4 @@ -package dev.adamko.kafkatorio.processor +package dev.adamko.kafkatorio.server.processor import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler.StreamThreadExceptionResponse diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/admin/KafkatorioKafkaAdmin.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/admin/KafkatorioKafkaAdmin.kt similarity index 91% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/admin/KafkatorioKafkaAdmin.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/admin/KafkatorioKafkaAdmin.kt index 02471bb..071a52f 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/admin/KafkatorioKafkaAdmin.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/admin/KafkatorioKafkaAdmin.kt @@ -1,6 +1,7 @@ -package dev.adamko.kafkatorio.processor.admin +package dev.adamko.kafkatorio.server.processor.admin -import dev.adamko.kafkatorio.processor.config.ApplicationProperties +import dev.adamko.kafkatorio.server.processor.allTopics +import dev.adamko.kafkatorio.server.config.ApplicationProperties import java.util.concurrent.TimeUnit import mu.KotlinLogging import org.apache.kafka.clients.admin.Admin diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/eventProcessor.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/eventProcessor.kt new file mode 100644 index 0000000..8dc6cf1 --- /dev/null +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/eventProcessor.kt @@ -0,0 +1,37 @@ +package dev.adamko.kafkatorio.server.processor + + +import dev.adamko.kafkatorio.server.socket.SyslogSocketServer +import dev.adamko.kafkatorio.server.processor.admin.KafkatorioKafkaAdmin +import dev.adamko.kafkatorio.server.config.ApplicationProperties +import dev.adamko.kafkatorio.server.web.websocket.WebmapWebsocketServer +import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch + + +suspend fun eventsProcessor( + appProps: ApplicationProperties, + syslogServer: SyslogSocketServer, + wsServer: WebmapWebsocketServer, +): Unit = coroutineScope { + + + val admin = KafkatorioKafkaAdmin(appProps) + admin.createKafkatorioTopics() + + +// val syslogServer = SyslogSocketServer(appProps) +// val wsServer = WebsocketServer() +// val tileServer = WebMapTileServer(appProps) + val topology = KafkatorioTopology(appProps, wsServer, syslogServer) + + + launch { + topology.start() + + println("launched KafkatorioTopology") + + awaitCancellation() + } +} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/admin/kafkatorioTopics.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/kafkatorioTopics.kt similarity index 98% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/admin/kafkatorioTopics.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/kafkatorioTopics.kt index 41c0206..e25ee8f 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/admin/kafkatorioTopics.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/kafkatorioTopics.kt @@ -1,4 +1,4 @@ -package dev.adamko.kafkatorio.processor.admin +package dev.adamko.kafkatorio.server.processor import dev.adamko.kafkatorio.schema.packets.ConfigurationUpdate import dev.adamko.kafkatorio.schema.packets.ConsoleChatUpdate diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/colourMapChunks.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/colourMapChunks.kt similarity index 96% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/colourMapChunks.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/colourMapChunks.kt index b790ffc..5800e33 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/colourMapChunks.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/colourMapChunks.kt @@ -1,9 +1,9 @@ -package dev.adamko.kafkatorio.processor.topology +package dev.adamko.kafkatorio.server.processor.topology -import dev.adamko.kafkatorio.processor.admin.TOPIC_MAP_CHUNK_COLOURED_032_STATE -import dev.adamko.kafkatorio.processor.admin.TOPIC_MAP_CHUNK_COLOURED_STATE -import dev.adamko.kafkatorio.processor.misc.DebounceProcessor.Companion.addDebounceProcessor -import dev.adamko.kafkatorio.processor.serdes.kxsBinary +import dev.adamko.kafkatorio.server.processor.TOPIC_MAP_CHUNK_COLOURED_032_STATE +import dev.adamko.kafkatorio.server.processor.TOPIC_MAP_CHUNK_COLOURED_STATE +import dev.adamko.kafkatorio.server.processor.DebounceProcessor.Companion.addDebounceProcessor +import dev.adamko.kafkatorio.library.kxsBinary import dev.adamko.kafkatorio.schema.common.ChunkSize import dev.adamko.kafkatorio.schema.common.ColourHex import dev.adamko.kafkatorio.schema.common.FactorioServerId diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/factorioServerPackets.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/factorioServerPackets.kt similarity index 90% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/factorioServerPackets.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/factorioServerPackets.kt index 283f062..013f635 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/factorioServerPackets.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/factorioServerPackets.kt @@ -1,9 +1,8 @@ -package dev.adamko.kafkatorio.processor.topology +package dev.adamko.kafkatorio.server.processor.topology - -import dev.adamko.kafkatorio.processor.admin.TOPIC_SRC_SERVER_LOG -import dev.adamko.kafkatorio.processor.admin.topicName -import dev.adamko.kafkatorio.processor.serdes.jsonMapper +import dev.adamko.kafkatorio.server.processor.TOPIC_SRC_SERVER_LOG +import dev.adamko.kafkatorio.server.processor.topicName +import dev.adamko.kafkatorio.server.config.jsonMapper import dev.adamko.kafkatorio.schema.common.FactorioServerId import dev.adamko.kafkatorio.schema.common.Tick import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/model.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/model.kt similarity index 93% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/model.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/model.kt index 558ecf0..72aa0ca 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/model.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/model.kt @@ -1,4 +1,4 @@ -package dev.adamko.kafkatorio.processor.topology +package dev.adamko.kafkatorio.server.processor.topology import com.sksamuel.scrimage.color.RGBColor import dev.adamko.kafkatorio.schema.common.ColourHex diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/packetDataStreams.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/packetDataStreams.kt similarity index 86% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/packetDataStreams.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/packetDataStreams.kt index 6ada2be..67a882a 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/packetDataStreams.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/packetDataStreams.kt @@ -1,7 +1,7 @@ -package dev.adamko.kafkatorio.processor.topology +package dev.adamko.kafkatorio.server.processor.topology -import dev.adamko.kafkatorio.processor.admin.topicName -import dev.adamko.kafkatorio.processor.serdes.jsonMapper +import dev.adamko.kafkatorio.server.processor.topicName +import dev.adamko.kafkatorio.server.config.jsonMapper import dev.adamko.kafkatorio.schema.common.FactorioServerId import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket import dev.adamko.kafkatorio.schema.packets.KafkatorioPacketData diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/prototypes.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/prototypes.kt similarity index 95% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/prototypes.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/prototypes.kt index 85401e5..f74fab9 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/prototypes.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/prototypes.kt @@ -1,6 +1,6 @@ -package dev.adamko.kafkatorio.processor.topology +package dev.adamko.kafkatorio.server.processor.topology -import dev.adamko.kafkatorio.processor.serdes.kxsBinary +import dev.adamko.kafkatorio.library.kxsBinary import dev.adamko.kafkatorio.schema.common.ColourHex import dev.adamko.kafkatorio.schema.common.FactorioPrototype import dev.adamko.kafkatorio.schema.common.FactorioServerId diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/saveMapTiles.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/saveMapTiles.kt similarity index 92% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/saveMapTiles.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/saveMapTiles.kt index b0da8d4..3d986dc 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/saveMapTiles.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/saveMapTiles.kt @@ -1,12 +1,12 @@ -package dev.adamko.kafkatorio.processor.topology +package dev.adamko.kafkatorio.server.processor.topology import com.sksamuel.scrimage.ImmutableImage import com.sksamuel.scrimage.ScaleMethod import com.sksamuel.scrimage.nio.PngWriter -import dev.adamko.kafkatorio.processor.admin.TOPIC_BROADCAST_TO_WEBSOCKET -import dev.adamko.kafkatorio.processor.admin.TOPIC_MAP_CHUNK_COLOURED_STATE -import dev.adamko.kafkatorio.processor.serdes.jsonMapper -import dev.adamko.kafkatorio.processor.serdes.kxsBinary +import dev.adamko.kafkatorio.server.processor.TOPIC_BROADCAST_TO_WEBSOCKET +import dev.adamko.kafkatorio.server.processor.TOPIC_MAP_CHUNK_COLOURED_STATE +import dev.adamko.kafkatorio.server.config.jsonMapper +import dev.adamko.kafkatorio.library.kxsBinary import dev.adamko.kafkatorio.schema.common.ColourHex import dev.adamko.kafkatorio.schema.common.FactorioServerId import dev.adamko.kafkatorio.schema.common.ServerMapChunkId diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/websocketBroadcast.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/websocketBroadcaster.kt similarity index 86% rename from modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/websocketBroadcast.kt rename to modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/websocketBroadcaster.kt index d80cb71..6783dd1 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/processor/topology/websocketBroadcast.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/websocketBroadcaster.kt @@ -1,10 +1,9 @@ -package dev.adamko.kafkatorio.processor.topology +package dev.adamko.kafkatorio.server.web.websocket -import dev.adamko.kafkatorio.processor.admin.TOPIC_BROADCAST_TO_WEBSOCKET -import dev.adamko.kafkatorio.processor.admin.topicName -import dev.adamko.kafkatorio.processor.tileserver.WebsocketServer +import dev.adamko.kafkatorio.library.jsonMapperKafkatorio +import dev.adamko.kafkatorio.server.processor.TOPIC_BROADCAST_TO_WEBSOCKET +import dev.adamko.kafkatorio.server.processor.topicName import dev.adamko.kafkatorio.schema.common.FactorioServerId -import dev.adamko.kafkatorio.schema.jsonMapperKafkatorio import dev.adamko.kafkatorio.schema.packets.EventServerPacket import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket import dev.adamko.kafkatorio.schema.packets.PlayerUpdate @@ -32,8 +31,8 @@ private const val pid = "websocketBroadcast" fun broadcastToWebsocket( - websocketServer: WebsocketServer, - builder: StreamsBuilder = StreamsBuilder(), + websocketServer: WebmapWebsocketServer, + builder: StreamsBuilder, ) { builder.broadcastKafkatorioPackets() @@ -45,7 +44,7 @@ fun broadcastToWebsocket( "$pid.websocket-server.send-message" ) { _, esPacket -> runBlocking { - websocketServer.sendMessage(jsonMapper.encodeToString(esPacket)) + websocketServer.sendMessageToClients(jsonMapper.encodeToString(esPacket)) } } } diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/socket/SyslogMsg.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/socket/SyslogMsg.kt new file mode 100644 index 0000000..26325e6 --- /dev/null +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/socket/SyslogMsg.kt @@ -0,0 +1,63 @@ +package dev.adamko.kafkatorio.server.socket + +import com.github.palindromicity.syslog.dsl.SyslogFieldKeys + +data class SyslogMsg( + val src: Map +) { + + val message: String? + get() = src[SyslogFieldKeys.MESSAGE.field] + + val headerAppName: String? + get() = src[SyslogFieldKeys.HEADER_APPNAME.field] + + val headerHostName: String? + get() = src[SyslogFieldKeys.HEADER_HOSTNAME.field] + + val headerPri: String? + get() = src[SyslogFieldKeys.HEADER_PRI.field] + + val headerPriSeverity: String? + get() = src[SyslogFieldKeys.HEADER_PRI_SEVERITY.field] + + val headerPriFacility: String? + get() = src[SyslogFieldKeys.HEADER_PRI_FACILITY.field] + + val headerProcId: String? + get() = src[SyslogFieldKeys.HEADER_PROCID.field] + + val headerTimestamp: String? + get() = src[SyslogFieldKeys.HEADER_TIMESTAMP.field] + + val headerMsgId: String? + get() = src[SyslogFieldKeys.HEADER_MSGID.field] + + val headerVersion: String? + get() = src[SyslogFieldKeys.HEADER_VERSION.field] + + val structuredBase: String? + get() = src[SyslogFieldKeys.STRUCTURED_BASE.field] + + val structuredElementIdFmt: String? + get() = src[SyslogFieldKeys.STRUCTURED_ELEMENT_ID_FMT.field] + + val structuredElementIdPnameFmt: String? + get() = src[SyslogFieldKeys.STRUCTURED_ELEMENT_ID_PNAME_FMT.field] + + val structuredElementIdPnamePattern: String? + get() = src[SyslogFieldKeys.STRUCTURED_ELEMENT_ID_PNAME_PATTERN.field] + + + companion object { + fun Map.toSyslogMsg(): SyslogMsg { + val map = entries.mapNotNull { (k, v) -> + when (v) { + is String -> k to v + else -> null + } + }.toMap() + return SyslogMsg(map) + } + } +} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/socket/SyslogSocketServer.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/socket/SyslogSocketServer.kt new file mode 100644 index 0000000..7b518d5 --- /dev/null +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/socket/SyslogSocketServer.kt @@ -0,0 +1,99 @@ +package dev.adamko.kafkatorio.server.socket + +import com.github.palindromicity.syslog.AllowableDeviations +import com.github.palindromicity.syslog.SyslogParser +import com.github.palindromicity.syslog.SyslogParserBuilder +import com.github.palindromicity.syslog.SyslogSpecification +import dev.adamko.kafkatorio.server.config.ApplicationProperties +import dev.adamko.kafkatorio.server.socket.SyslogMsg.Companion.toSyslogMsg +import io.ktor.network.selector.SelectorManager +import io.ktor.network.sockets.Socket +import io.ktor.network.sockets.aSocket +import io.ktor.network.sockets.openReadChannel +import io.ktor.utils.io.readUTF8Line +import java.util.EnumSet +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import kotlinx.coroutines.yield + + +class SyslogSocketServer( + appProps: ApplicationProperties, +) { + + private val selectorManager: SelectorManager = SelectorManager(Dispatchers.IO) + + + private val serverSocketTcp = aSocket(selectorManager) + .tcp() + .bind( + appProps.socketServerHost, + appProps.socketServerPort, + ) + + + private val syslogParser: SyslogParser = SyslogParserBuilder() + .withDeviations(EnumSet.of(AllowableDeviations.PRIORITY, AllowableDeviations.VERSION)) + .forSpecification(SyslogSpecification.RFC_5424) + .build() + + + private val _messages: MutableSharedFlow = MutableSharedFlow() + val messages: SharedFlow + get() = _messages.asSharedFlow() + + + suspend fun start(): Unit = coroutineScope { + log("started listening: ${serverSocketTcp.localAddress}") + + while (isActive) { + val socket: Socket = serverSocketTcp.accept() + log("new socket ${socket.description()}") + + launch { + val channel = socket.openReadChannel() + try { + while (socket.socketContext.isActive) { + val line = runCatching { + channel.readUTF8Line() + }.fold( + onSuccess = { line -> + log("received '$line' from $socket") + line + }, + onFailure = { e -> + log("reading line from socket failed ${socket.description()}, cause: $e") + null + }, + ) + if (line != null) { + + val syslog = syslogParser.parseLine(line).toSyslogMsg() + + _messages.emit(syslog) + } + + yield() + } + } catch (e: Exception) { + log("closing socket ${socket.description()}, cause: $e") + withContext(Dispatchers.IO) { socket.close() } + } + } + + yield() + } + } + + companion object { + private fun log(msg: String) = println("[SyslogSocketServer] $msg") + + private fun Socket.description(): String = "Socket[local:$localAddress, remote:$remoteAddress]" + } +} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/syslogSocketServer.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/syslogSocketServer.kt deleted file mode 100644 index ff78865..0000000 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/syslogSocketServer.kt +++ /dev/null @@ -1,152 +0,0 @@ -package dev.adamko.kafkatorio.server - -import com.github.palindromicity.syslog.AllowableDeviations -import com.github.palindromicity.syslog.SyslogParser -import com.github.palindromicity.syslog.SyslogParserBuilder -import com.github.palindromicity.syslog.SyslogSpecification -import com.github.palindromicity.syslog.dsl.SyslogFieldKeys -import dev.adamko.kafkatorio.processor.config.ApplicationProperties -import dev.adamko.kafkatorio.server.SyslogMsg.Companion.toSyslogMsg -import io.ktor.network.selector.SelectorManager -import io.ktor.network.sockets.aSocket -import io.ktor.network.sockets.awaitClosed -import io.ktor.network.sockets.openReadChannel -import io.ktor.server.application.Application -import io.ktor.utils.io.readUTF8Line -import java.util.EnumSet -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.asSharedFlow -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch -import kotlinx.coroutines.yield - - -fun Application.syslogSocketServer(appProps: ApplicationProperties) { - val server = SyslogSocketServer(appProps) - - launch { - server.start() - } -} - - -class SyslogSocketServer( - appProps: ApplicationProperties, -) { - - private val selectorManager: SelectorManager = SelectorManager(Dispatchers.IO) - - - private val serverSocketTcp = aSocket(selectorManager) - .tcp() - .bind( - appProps.socketServerHost, - appProps.socketServerPort, - ) - - - private val syslogParser: SyslogParser = SyslogParserBuilder() - .withDeviations(EnumSet.of(AllowableDeviations.PRIORITY, AllowableDeviations.VERSION)) - .forSpecification(SyslogSpecification.RFC_5424) - .build() - - - private val _messages: MutableSharedFlow = MutableSharedFlow() - val messages: SharedFlow - get() = _messages.asSharedFlow() - - - suspend fun start(): Unit = coroutineScope { - println("[SyslogSocketServer] started listening: ${serverSocketTcp.localAddress}") - - while (isActive) { - val socket = serverSocketTcp.accept() - - launch { - val channel = socket.openReadChannel() - try { - while (socket.socketContext.isActive) { - val line = runCatching { channel.readUTF8Line() }.getOrNull() - if (line != null) { - - println("[SyslogSocketServer] received: $line") - - val syslog = syslogParser.parseLine(line).toSyslogMsg() - - _messages.emit(syslog) - } - - yield() - } - } catch (e: Exception) { - socket.awaitClosed() - } - } - - yield() - } - } -} - - -data class SyslogMsg( - val src: Map -) { - - val message: String? - get() = src[SyslogFieldKeys.MESSAGE.field] - - val headerAppName: String? - get() = src[SyslogFieldKeys.HEADER_APPNAME.field] - - val headerHostName: String? - get() = src[SyslogFieldKeys.HEADER_HOSTNAME.field] - - val headerPri: String? - get() = src[SyslogFieldKeys.HEADER_PRI.field] - - val headerPriSeverity: String? - get() = src[SyslogFieldKeys.HEADER_PRI_SEVERITY.field] - - val headerPriFacility: String? - get() = src[SyslogFieldKeys.HEADER_PRI_FACILITY.field] - - val headerProcId: String? - get() = src[SyslogFieldKeys.HEADER_PROCID.field] - - val headerTimestamp: String? - get() = src[SyslogFieldKeys.HEADER_TIMESTAMP.field] - - val headerMsgId: String? - get() = src[SyslogFieldKeys.HEADER_MSGID.field] - - val headerVersion: String? - get() = src[SyslogFieldKeys.HEADER_VERSION.field] - - val structuredBase: String? - get() = src[SyslogFieldKeys.STRUCTURED_BASE.field] - - val structuredElementIdFmt: String? - get() = src[SyslogFieldKeys.STRUCTURED_ELEMENT_ID_FMT.field] - - val structuredElementIdPnameFmt: String? - get() = src[SyslogFieldKeys.STRUCTURED_ELEMENT_ID_PNAME_FMT.field] - - val structuredElementIdPnamePattern: String? - get() = src[SyslogFieldKeys.STRUCTURED_ELEMENT_ID_PNAME_PATTERN.field] - - companion object { - fun Map.toSyslogMsg(): SyslogMsg { - val map = entries.mapNotNull { (k, v) -> - when (v) { - is String -> k to v - else -> null - } - }.toMap() - return SyslogMsg(map) - } - } -} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/rest/factorioServersRoutes.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/rest/factorioServersRoutes.kt new file mode 100644 index 0000000..01035d2 --- /dev/null +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/rest/factorioServersRoutes.kt @@ -0,0 +1,121 @@ +package dev.adamko.kafkatorio.server.web.rest + +import dev.adamko.kafkatorio.schema.common.FactorioServerId +import dev.adamko.kafkatorio.schema.common.PlayerIndex +import dev.adamko.kafkatorio.schema.common.SurfaceIndex +import dev.adamko.kafkatorio.schema.common.TilePngFilename +import dev.adamko.kafkatorio.server.config.ApplicationProperties +import io.ktor.http.HttpStatusCode +import io.ktor.http.content.EntityTagVersion +import io.ktor.http.content.versions +import io.ktor.resources.Resource +import io.ktor.server.application.ApplicationCall +import io.ktor.server.application.application +import io.ktor.server.application.call +import io.ktor.server.application.log +import io.ktor.server.http.content.LastModifiedVersion +import io.ktor.server.resources.get +import io.ktor.server.response.respond +import io.ktor.server.response.respondFile +import io.ktor.server.routing.Routing +import io.ktor.util.combineSafe +import io.ktor.util.pipeline.PipelineContext +import kotlin.io.path.Path +import kotlinx.serialization.Serializable + + +fun Routing.factorioServersRoutes( + appProps: ApplicationProperties, +) { + + get { + call.respond(HttpStatusCode.NotImplemented) + } + + get { tile -> + handleTileRequest(tile, appProps) + } +} + + +private suspend fun PipelineContext.handleTileRequest( + tile: FactorioServer.MapData.Tile, + appProps: ApplicationProperties, +) { + + val tileFilename = TilePngFilename( + tile.serverId, + tile.surfaceIndex, + tile.zoomLevel, + tile.chunkX, + tile.chunkY, + ) + + val tileFile = appProps.serverDataDir.combineSafe(Path(tileFilename.value)) + + if (tileFile.exists()) { + call.respondFile(tileFile) { + versions = versions + listOf( + EntityTagVersion(tileFile.lastModified().hashCode().toString()), + LastModifiedVersion(tileFile.lastModified()), + ) + } + } else { + call.respond(HttpStatusCode.NotFound) + } +} + + +@Serializable +@Resource("kafkatorio/data/servers") +private class FactorioServers + + +@Serializable +@Resource("kafkatorio/data/servers/{factorioServerId}") +data class FactorioServer( + val factorioServerId: FactorioServerId, +) { + + @Serializable + @Resource("map") + data class MapData( + val server: FactorioServer, + ) { + + @Serializable + @Resource("tiles/s{surfaceIndex}/z{zoomLevel}/x{chunkX}/y{chunkY}.png") + data class Tile( + val mapData: MapData, + val surfaceIndex: SurfaceIndex, + val zoomLevel: Int, + val chunkX: Int, + val chunkY: Int, + ) + + @Serializable + @Resource("buildings/s{surfaceIndex}") + data class Buildings( + val mapData: MapData, + val surfaceIndex: SurfaceIndex, + // a list of buildings... (Sealed interface, different types?) + ) + } + + @Serializable + @Resource("players") + data class Players( + val server: FactorioServer, + ) + + @Serializable + @Resource("{playerId}") + data class Player( + val server: FactorioServer, + val playerIndex: PlayerIndex, + ) +} + + +private val FactorioServer.MapData.Tile.serverId: FactorioServerId + get() = mapData.server.factorioServerId diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/rest/restApi.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/rest/restApi.kt new file mode 100644 index 0000000..8aef3a3 --- /dev/null +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/rest/restApi.kt @@ -0,0 +1,50 @@ +package dev.adamko.kafkatorio.server.web.rest + +import dev.adamko.kafkatorio.server.config.ApplicationProperties +import io.ktor.http.ContentType +import io.ktor.http.HttpStatusCode +import io.ktor.serialization.kotlinx.json.json +import io.ktor.server.application.Application +import io.ktor.server.application.install +import io.ktor.server.application.log +import io.ktor.server.plugins.autohead.AutoHeadResponse +import io.ktor.server.plugins.callloging.CallLogging +import io.ktor.server.plugins.compression.Compression +import io.ktor.server.plugins.compression.excludeContentType +import io.ktor.server.plugins.compression.minimumSize +import io.ktor.server.plugins.conditionalheaders.ConditionalHeaders +import io.ktor.server.plugins.contentnegotiation.ContentNegotiation +import io.ktor.server.plugins.partialcontent.PartialContent +import io.ktor.server.plugins.statuspages.StatusPages +import io.ktor.server.resources.Resources +import io.ktor.server.response.respondText +import io.ktor.server.routing.routing + + +fun Application.webmapTileServer(appProps: ApplicationProperties) { + + install(AutoHeadResponse) + install(CallLogging) + install(Compression) { + default() + minimumSize(1024) + excludeContentType(ContentType.Video.Any) + } + install(ConditionalHeaders) + install(ContentNegotiation) { + json() + } + install(PartialContent) + install(Resources) + + install(StatusPages) { + exception { call, cause -> + this@webmapTileServer.log.error("$call caused exception - returning 500", cause) + call.respondText(text = "500: $cause", status = HttpStatusCode.InternalServerError) + } + } + + routing { + factorioServersRoutes(appProps) + } +} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/webServer.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/webServer.kt new file mode 100644 index 0000000..4fe626e --- /dev/null +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/webServer.kt @@ -0,0 +1,27 @@ +package dev.adamko.kafkatorio.server.web + +import dev.adamko.kafkatorio.server.config.ApplicationProperties +import dev.adamko.kafkatorio.server.web.rest.webmapTileServer +import dev.adamko.kafkatorio.server.web.websocket.WebmapWebsocketServer +import dev.adamko.kafkatorio.server.web.websocket.webmapWebsocketServer +import io.ktor.server.cio.CIO +import io.ktor.server.engine.embeddedServer +import kotlinx.coroutines.coroutineScope + + +suspend fun startWebServer( + appProps: ApplicationProperties, + wsServer: WebmapWebsocketServer, +): Unit = coroutineScope { + + embeddedServer( + factory = CIO, + port = appProps.webPort.value, + ) { + + webmapWebsocketServer(wsServer) + + webmapTileServer(appProps) + + }.start(wait = true) +} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/websocket/WebmapWebsocketServer.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/websocket/WebmapWebsocketServer.kt new file mode 100644 index 0000000..560ba57 --- /dev/null +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/websocket/WebmapWebsocketServer.kt @@ -0,0 +1,112 @@ +package dev.adamko.kafkatorio.server.web.websocket + +import io.ktor.websocket.DefaultWebSocketSession +import io.ktor.websocket.Frame +import io.ktor.websocket.send +import java.util.concurrent.atomic.AtomicInteger +import kotlin.time.Duration.Companion.seconds +import kotlin.time.TimeSource +import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.isActive +import kotlinx.coroutines.job +import kotlinx.coroutines.launch +import kotlinx.coroutines.yield + + +class WebmapWebsocketServer { + + private val startTime = TimeSource.Monotonic.markNow() + + private val clients: MutableStateFlow> = MutableStateFlow(emptyList()) + + private val messagesToClients: MutableSharedFlow = MutableSharedFlow( + extraBufferCapacity = Int.MAX_VALUE, + onBufferOverflow = BufferOverflow.DROP_OLDEST + ) + + private val messagesFromClients: MutableSharedFlow = MutableSharedFlow( + extraBufferCapacity = Int.MAX_VALUE, + onBufferOverflow = BufferOverflow.DROP_OLDEST + ) + + + suspend fun bindClient(session: DefaultWebSocketSession): Unit = coroutineScope { + val client = WSConnection(session) + + clients.update { clients -> clients + client } + + client.coroutineContext.job.invokeOnCompletion { e -> + log("client ${client.name} completed ${e ?: "successfully"}") + clients.update { clients -> + (clients - client).filter { it.isActive } + } + } + + messagesToClients.onEach { msg -> + runCatching { + if (client.isActive) { + client.outgoing.send(Frame.Text(msg)) + } + } + }.launchIn(client) + + client.launch { + client.incoming.receiveAsFlow().collect(messagesFromClients) + } + +// client.launch { + while (isActive) { + runCatching { + client.send("elapsed ${startTime.elapsedNow()}") + } + delay(10.seconds) + yield() + } +// } + +// awaitCancellation() + } + + + suspend fun sendMessageToClients(msg: String) { + log("sending message to clients: $msg") + messagesToClients.emit(msg) + } + + + private data class WSConnection( + private val session: DefaultWebSocketSession, + ) : DefaultWebSocketSession by session { + val name: String = "user${lastId.getAndIncrement()}" + + override suspend fun send(frame: Frame): Unit = runCatching { + super.send(frame) + }.fold( + onSuccess = { log("sent message to client $name: $frame") }, + onFailure = { e -> log("failed to send message to client $name: $e") } + ) + + override fun equals(other: Any?): Boolean = name == other + override fun hashCode(): Int = name.hashCode() + + companion object { + private val lastId = AtomicInteger(0) + } + } + + + companion object { + + private fun log(msg: String) = println("[WebmapWebsocketServer] $msg") + + } +} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/websocket/wsServer.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/websocket/wsServer.kt new file mode 100644 index 0000000..ea2b51e --- /dev/null +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/websocket/wsServer.kt @@ -0,0 +1,34 @@ +package dev.adamko.kafkatorio.server.web.websocket + +import io.ktor.server.application.Application +import io.ktor.server.application.install +import io.ktor.server.routing.routing +import io.ktor.server.websocket.WebSockets +import io.ktor.server.websocket.webSocket +import io.ktor.websocket.WebSocketDeflateExtension +import java.util.zip.Deflater + + +fun Application.webmapWebsocketServer( + wsServer: WebmapWebsocketServer, +) { + install(WebSockets) { + extensions { + install(WebSocketDeflateExtension) { + // Compression level to use for java.util.zip.Deflater + compressionLevel = Deflater.DEFAULT_COMPRESSION + + // Prevent compressing small outgoing frames + compressIfBiggerThan(bytes = 4 * 1024) + } + } + } + + routing { + // TODO only send a ws client message for a single Factorio-sever. Make the URL server specific. + // /kafkatorio/data/servers/{serverId}/ws + webSocket("kafkatorio/ws") { + wsServer.bindClient(this) + } + } +} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/webmapTileServer.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/webmapTileServer.kt deleted file mode 100644 index 05853b7..0000000 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/webmapTileServer.kt +++ /dev/null @@ -1,148 +0,0 @@ -package dev.adamko.kafkatorio.server - -import dev.adamko.kafkatorio.processor.config.ApplicationProperties -import dev.adamko.kafkatorio.schema.common.FactorioServerId -import dev.adamko.kafkatorio.schema.common.PlayerIndex -import dev.adamko.kafkatorio.schema.common.SurfaceIndex -import dev.adamko.kafkatorio.schema.common.TilePngFilename -import io.ktor.http.ContentType -import io.ktor.http.HttpStatusCode -import io.ktor.http.content.EntityTagVersion -import io.ktor.http.content.versions -import io.ktor.resources.Resource -import io.ktor.serialization.kotlinx.json.json -import io.ktor.server.application.Application -import io.ktor.server.application.ApplicationCall -import io.ktor.server.application.call -import io.ktor.server.application.install -import io.ktor.server.http.content.LastModifiedVersion -import io.ktor.server.plugins.autohead.AutoHeadResponse -import io.ktor.server.plugins.compression.Compression -import io.ktor.server.plugins.compression.excludeContentType -import io.ktor.server.plugins.compression.minimumSize -import io.ktor.server.plugins.conditionalheaders.ConditionalHeaders -import io.ktor.server.plugins.contentnegotiation.ContentNegotiation -import io.ktor.server.plugins.partialcontent.PartialContent -import io.ktor.server.resources.Resources -import io.ktor.server.resources.get -import io.ktor.server.response.respond -import io.ktor.server.response.respondFile -import io.ktor.server.routing.routing -import io.ktor.util.combineSafe -import io.ktor.util.pipeline.PipelineContext -import kotlin.io.path.Path -import kotlinx.serialization.Serializable - - -fun Application.webmapTileServer(appProps: ApplicationProperties) { - - install(AutoHeadResponse) - install(Compression) { - default() - minimumSize(1024) - excludeContentType(ContentType.Video.Any) - } - install(ConditionalHeaders) - install(ContentNegotiation) { - json() - } - install(PartialContent) - install(Resources) - - val server = WebmapTileServer(appProps) - - routing { - with(server) { - - get { tile -> - handleTileRequest(tile) - } - - get { - - } - } - } -} - - -private class WebmapTileServer( - private val appProps: ApplicationProperties -) { - private val serverDataDir by appProps::serverDataDir - - suspend fun PipelineContext.handleTileRequest( - tile: FactorioServers.FactorioServer.MapData.Tile - ) { - - val tileFilename = TilePngFilename( - tile.serverId, - tile.surfaceIndex, - tile.zoomLevel, - tile.chunkX, - tile.chunkY, - ) - - val tileFile = serverDataDir.combineSafe(Path(tileFilename.value)) - - if (tileFile.exists()) { - call.respondFile(tileFile) { - versions = versions + listOf( - EntityTagVersion(tileFile.lastModified().hashCode().toString()), - LastModifiedVersion(tileFile.lastModified()), - ) - } - } else { - call.respond(HttpStatusCode.NotFound) - } - } -} - - -@Serializable -@Resource("servers") -private class FactorioServers { - - @Serializable - @Resource("{factorioServerId}") - data class FactorioServer( - val factorioServerId: FactorioServerId, - ) { - - @Serializable - @Resource("map") - class MapData { - - @Serializable - @Resource("tiles/s{surfaceIndex}/z{zoomLevel}/x{chunkX}/y{chunkY}.png") - data class Tile( - val parent: FactorioServer, - val surfaceIndex: SurfaceIndex, - val zoomLevel: Int, - val chunkX: Int, - val chunkY: Int, - ) { - val serverId: FactorioServerId by parent::factorioServerId - } - - @Serializable - @Resource("buildings/s{surfaceIndex}") - data class Buildings( - val surfaceIndex: SurfaceIndex, - // a list of buildings... (Sealed interface, different types?) - ) - - } - - @Serializable - @Resource("players") - class Players { - - @Serializable - @Resource("{playerId}") - data class Id( - val playerIndex: PlayerIndex, - ) - } - } -} diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/webmapWebsocketServer.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/webmapWebsocketServer.kt deleted file mode 100644 index 0ae3f8c..0000000 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/webmapWebsocketServer.kt +++ /dev/null @@ -1,130 +0,0 @@ -package dev.adamko.kafkatorio.server - -import dev.adamko.kafkatorio.processor.config.ApplicationProperties -import io.ktor.server.application.Application -import io.ktor.server.application.install -import io.ktor.server.routing.routing -import io.ktor.server.websocket.WebSockets -import io.ktor.server.websocket.webSocket -import io.ktor.websocket.DefaultWebSocketSession -import io.ktor.websocket.Frame -import io.ktor.websocket.WebSocketDeflateExtension -import io.ktor.websocket.send -import java.util.concurrent.atomic.AtomicInteger -import java.util.zip.Deflater -import kotlin.time.Duration.Companion.seconds -import kotlin.time.TimeSource -import kotlinx.coroutines.channels.BufferOverflow -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.receiveAsFlow -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.isActive -import kotlinx.coroutines.job -import kotlinx.coroutines.launch - - -fun Application.webmapWebsocketServer() { - install(WebSockets) { - extensions { - install(WebSocketDeflateExtension) { - // Compression level to use for java.util.zip.Deflater - compressionLevel = Deflater.DEFAULT_COMPRESSION - - // Prevent compressing small outgoing frames - compressIfBiggerThan(bytes = 4 * 1024) - } - } - } - - val wsServer = WebmapWebsocketServer() - - routing { - - webSocket("/ws") { - wsServer.bindClient(this) - } - } -} - - -private class WebmapWebsocketServer { - - private val startTime = TimeSource.Monotonic.markNow() - - private val clients: MutableStateFlow> = MutableStateFlow(emptySet()) - - private val messagesToClients: MutableSharedFlow = MutableSharedFlow( - extraBufferCapacity = Int.MAX_VALUE, - onBufferOverflow = BufferOverflow.DROP_OLDEST - ) - - private val messagesFromClients: MutableSharedFlow = MutableSharedFlow( - extraBufferCapacity = Int.MAX_VALUE, - onBufferOverflow = BufferOverflow.DROP_OLDEST - ) - - suspend fun bindClient(session: DefaultWebSocketSession) { - val client = WSConnection(session) - - clients.update { clients -> clients + client } - - messagesToClients.onEach { msg -> - runCatching { - client.send(msg) - } - }.launchIn(client) - - client.launch { - client.incoming.receiveAsFlow() - .collect(messagesFromClients) - } - - client.launch { - while (isActive) { - runCatching { - client.send("elapsed ${startTime.elapsedNow()}") - } - delay(10.seconds) - } - } - - client.coroutineContext.job.invokeOnCompletion { - log("client ${client.name} completed") - clients.update { clients -> clients - client } - } - } - - - suspend fun sendMessageToClients(msg: String) { - log("sending message to clients: $msg") - messagesToClients.emit(msg) - } -} - - -private data class WSConnection( - private val session: DefaultWebSocketSession, -) : DefaultWebSocketSession by session { - val name: String = "user${lastId.getAndIncrement()}" - - override suspend fun send(frame: Frame): Unit = runCatching { - super.send(frame) - }.fold( - onSuccess = { log("sent message to client $name: $frame") }, - onFailure = { log("failed to send message to client $name: $frame") } - ) - - override fun equals(other: Any?): Boolean = name == other - override fun hashCode(): Int = name.hashCode() - - companion object { - private val lastId = AtomicInteger(0) - } -} - - -private fun log(msg: String) = println("[WebmapWebsocketServer] $msg") diff --git a/modules/events-server/src/main/resources/config.yml b/modules/events-server/src/main/resources/config.yml index 5c95abf..a5117f3 100644 --- a/modules/events-server/src/main/resources/config.yml +++ b/modules/events-server/src/main/resources/config.yml @@ -1,11 +1,11 @@ # Factorio Events Processor config web-port: ${SERVER_PORT:-8080} -servers-data-dir: ${SERVER_DATA_DIR:-./server-data} +server-data-dir: ${SERVER_DATA_DIR:-./server-data} socket-server-host: ${SOCKET_SERVER_HOST:-127.0.0.1} -socket-server-port: ${SOCKET_SERVER_PORT:-9002} +socket-server-port: ${SOCKET_SERVER_PORT:-12092} kafka-admin-config: diff --git a/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/misc/DebounceProcessorTest.kt b/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/misc/DebounceProcessorTest.kt deleted file mode 100644 index a8d777d..0000000 --- a/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/misc/DebounceProcessorTest.kt +++ /dev/null @@ -1,49 +0,0 @@ -package dev.adamko.kafkatorio.processor.misc - -import io.kotest.core.spec.style.FunSpec -import io.kotest.core.spec.style.Test -import io.mockk.every -import io.mockk.mockk -import kotlin.time.Duration.Companion.minutes -import org.apache.kafka.common.serialization.Serdes -import org.apache.kafka.streams.StreamsBuilder -import org.apache.kafka.streams.Topology -import org.apache.kafka.streams.state.KeyValueIterator -import org.apache.kafka.streams.state.TimestampedKeyValueStore - -class DebounceProcessorTest : FunSpec({ - - -}) { - @Test - fun blah() { - - -// val topology = Topology() -// -// topology.addProcessor( -// "blah", -// debounceProcessor( -// 1.minutes, -// "asdasda", -// Serdes.String(), -// Serdes.String() -// ) -// ) - - -// val streamsBuilder = StreamsBuilder() -// -// streamsBuilder -// .stream("input-topic") -// .process( -// debounceProcessor( -// 1.minutes, -// "input-topic-debounce-store", -// Serdes.String(), -// Serdes.String(), -// ), -// ) - - } -} diff --git a/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/misc/serdeSize.kt b/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/misc/serdeSize.kt index ec0591e..502ed3e 100644 --- a/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/misc/serdeSize.kt +++ b/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/misc/serdeSize.kt @@ -1,14 +1,14 @@ package dev.adamko.kafkatorio.processor.misc -import dev.adamko.kafkatorio.processor.serdes.kxsBinary +import dev.adamko.kafkatorio.library.kxsBinary import dev.adamko.kafkatorio.schema.common.ServerMapChunkId -import dev.adamko.kafkatorio.processor.topology.ServerMapChunkTiles import dev.adamko.kafkatorio.schema.common.ChunkSize import dev.adamko.kafkatorio.schema.common.ColourHex import dev.adamko.kafkatorio.schema.common.FactorioServerId import dev.adamko.kafkatorio.schema.common.MapChunkPosition import dev.adamko.kafkatorio.schema.common.MapTilePosition import dev.adamko.kafkatorio.schema.common.SurfaceIndex +import dev.adamko.kafkatorio.server.processor.topology.ServerMapChunkTiles import java.util.UUID import kotlinx.serialization.encodeToByteArray import org.junit.jupiter.api.Test @@ -24,7 +24,7 @@ class Blah { serverId = FactorioServerId(UUID.randomUUID().toString()), chunkPosition = MapChunkPosition(Int.MAX_VALUE, Int.MAX_VALUE), surfaceIndex = SurfaceIndex(UInt.MAX_VALUE), - chunkSize = ChunkSize.MAX + chunkSize = ChunkSize.MAX, ), buildMap { repeat(512) { x -> diff --git a/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/topology/GroupMapChunksTest.kt b/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/topology/GroupMapChunksTest.kt index 98b0138..56cb643 100644 --- a/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/topology/GroupMapChunksTest.kt +++ b/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/topology/GroupMapChunksTest.kt @@ -1,8 +1,8 @@ package dev.adamko.kafkatorio.processor.topology -//import dev.adamko.kafkatorio.processor.admin.TOPIC_GROUPED_MAP_CHUNKS_STATE -//import dev.adamko.kafkatorio.processor.serdes.jsonMapper -//import dev.adamko.kafkatorio.processor.serdes.kxsBinary +//import dev.adamko.kafkatorio.server.processor.TOPIC_GROUPED_MAP_CHUNKS_STATE +//import dev.adamko.kafkatorio.processor.config.getJsonMapper +//import dev.adamko.kafkatorio.library.getKxsBinary //import dev.adamko.kafkatorio.schema.common.Colour //import dev.adamko.kafkatorio.schema.common.ColourHex //import dev.adamko.kafkatorio.schema.common.MapChunkPosition diff --git a/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/topology/SaveMapChunksTest.kt b/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/server/processor/topology/SaveMapChunksTest.kt similarity index 98% rename from modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/topology/SaveMapChunksTest.kt rename to modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/server/processor/topology/SaveMapChunksTest.kt index d1a8fb5..d7a07fa 100644 --- a/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/processor/topology/SaveMapChunksTest.kt +++ b/modules/events-server/src/test/kotlin/dev/adamko/kafkatorio/server/processor/topology/SaveMapChunksTest.kt @@ -1,6 +1,6 @@ -package dev.adamko.kafkatorio.processor.topology +package dev.adamko.kafkatorio.server.processor.topology -import dev.adamko.kafkatorio.processor.serdes.kxsBinary +import dev.adamko.kafkatorio.library.kxsBinary import dev.adamko.kafkatorio.schema.common.ChunkSize import dev.adamko.kafkatorio.schema.common.ColourHex import dev.adamko.kafkatorio.schema.common.FactorioServerId diff --git a/modules/infra-factorio-server/src/docker-compose.yml b/modules/infra-factorio-server/src/docker-compose.yml index 3b12252..34fd329 100644 --- a/modules/infra-factorio-server/src/docker-compose.yml +++ b/modules/infra-factorio-server/src/docker-compose.yml @@ -19,7 +19,7 @@ services: logging: driver: syslog options: - syslog-address: "tcp://host.docker.internal:9002" + syslog-address: "tcp://host.docker.internal:12092" syslog-format: "rfc5424" # environment: diff --git a/modules/web-map/build.gradle.kts b/modules/web-map/build.gradle.kts index 8a02c87..ef2b535 100644 --- a/modules/web-map/build.gradle.kts +++ b/modules/web-map/build.gradle.kts @@ -17,23 +17,6 @@ kvision { } -rootProject.extensions.configure { - // https://github.com/rjaros/kvision/issues/410 - versions.webpackCli.version = "4.10.0" - versions.webpackDevServer.version = "4.9.2" -} - -rootProject.extensions.configure { - resolution("http-proxy-middleware", "^2.0.6") -} - -//rootProject.afterEvaluate { -// extensions.configure { -// // https://github.com/rjaros/kvision/issues/410 -// versions.webpackCli.version = "4.10.0" -// } -//} - afterEvaluate { rootProject.extensions.configure { // https://github.com/rjaros/kvision/issues/410 @@ -58,12 +41,12 @@ kotlin { open = false, port = 3000, proxy = mutableMapOf( - "/tiles" to mapOf( + "/kafkatorio/data/servers" to mapOf( "target" to "http://localhost:12080", "secure" to false, "changeOrigin" to true, ), - "/ws/foo" to mapOf( + "/kafkatorio/ws" to mapOf( "target" to "ws://localhost:12080", // "secure" to false, "ws" to true, @@ -104,12 +87,10 @@ kotlin { implementation(libs.kotlinx.coroutines.core) - implementation(projects.modules.eventsSchema) + implementation(projects.modules.eventsLibrary) implementation(libs.kotlinx.html) - implementation(projects.modules.eventsSchema) - implementation(libs.kotlinx.nodejs) implementation(libs.kotlinx.html) @@ -176,28 +157,3 @@ fun KotlinDependencyHandler.kvision( // resolution("webpack-dev-server", "4.9.1") // } //} - - -//evaluationDependsOn(rootProject.path) -//evaluationDependsOn(projects.modules.eventsSchema.dependencyProject.path) - - -//// stop warnings when building -//tasks.configureEach { -// when (name) { -// "productionExecutableCompileSync" -> -// dependsOn(taskProvider("compileProductionExecutableKotlinJs")) -// "testTestDevelopmentExecutableCompileSync" -> -// dependsOn(taskProvider("compileTestDevelopmentExecutableKotlinJs")) -//// "jsTestTestDevelopmentExecutableCompileSync" -> -//// dependsOn(taskProvider("compileTestDevelopmentExecutableKotlinFrontend")) -//// "jsProductionExecutableCompileSync" -> -//// dependsOn(taskProvider("compileProductionExecutableKotlinFrontend")) -// "browserDevelopmentRun" -> -// dependsOn(taskProvider("browserDevelopmentWebpack")) -// "browserDevelopmentWebpack" -> -// dependsOn(taskProvider("assemble")) -// "browserProductionWebpack" -> -// dependsOn(taskProvider("developmentExecutableCompileSync")) -// } -//} diff --git a/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/App.kt b/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/App.kt index 6d09996..03ac670 100644 --- a/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/App.kt +++ b/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/App.kt @@ -77,12 +77,9 @@ class App( wsService.packetsFlow .filterIsInstance() - .onEach { - println("[packetsFlow] triggering tile refresh ${it.filename.value}") - gameState.map.refreshUpdatedTilePng( -// doc, window, - it.filename - ) + .onEach { tileSavedEvent -> + println("[packetsFlow] triggering tile refresh ${tileSavedEvent.filename.value}") + gameState.map.refreshUpdatedTilePng(tileSavedEvent.filename) }.launchIn(this) } diff --git a/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/ApplicationProperties.kt b/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/ApplicationProperties.kt index 38d4a7e..50fcd59 100644 --- a/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/ApplicationProperties.kt +++ b/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/ApplicationProperties.kt @@ -8,5 +8,5 @@ object Props { get() = window.location.href .replace("http://", "ws://") .replace("https://", "wss://") + - "ws/foo" + "kafkatorio/ws" } diff --git a/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/externals/leaflet.kt b/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/externals/leaflet.kt index 0c59e22..b72d539 100644 --- a/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/externals/leaflet.kt +++ b/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/externals/leaflet.kt @@ -14,6 +14,7 @@ inline var TileLayer.tileOnLoad: TileOnLoadFn? } +/** @see [tileOnLoad] */ typealias TileOnLoadFn = (done: DoneCallback, tile: HTMLElement) -> Unit diff --git a/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/json.kt b/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/json.kt index 7acdff3..3dd2fba 100644 --- a/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/json.kt +++ b/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/json.kt @@ -1,6 +1,6 @@ package dev.adamko.kafkatorio.webmap -import dev.adamko.kafkatorio.schema.jsonMapperKafkatorio +import dev.adamko.kafkatorio.library.jsonMapperKafkatorio import kotlinx.serialization.json.Json val jsonMapper = Json { diff --git a/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/map.kt b/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/map.kt index 8c40db5..9ee6b7c 100644 --- a/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/map.kt +++ b/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/map.kt @@ -31,7 +31,7 @@ import org.w3c.fetch.RequestMode class FactorioMap( - private val tileUrlTemplate: String = """/tiles/s1/z{z}/x{x}/y{y}.png""", + private val tileUrlTemplate: String = """/kafkatorio/data/servers/syslog-test/map/tiles/s1/z{z}/x{x}/y{y}.png""", ) { val kvMap: Maps = Maps { @@ -89,9 +89,7 @@ class FactorioMap( .querySelectorAll("img.leaflet-tile-loaded") .asList() .filterIsInstance() - .filter { img -> - tilePngFilename.value in img.src - } + .filter { img -> tilePngFilename.value in img.src } .forEach { img -> val imgSrc = img.src diff --git a/settings.gradle.kts b/settings.gradle.kts index 80c5d2c..b72e1b1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,8 +2,7 @@ rootProject.name = "kafkatorio" include( ":modules:events-mod", - ":modules:events-schema", - ":modules:events-processor", + ":modules:events-library", ":modules:events-server", ":modules:infra-factorio-client",