From d0d7799d62ee215ba6953e0082e7429f59e60c1a Mon Sep 17 00:00:00 2001 From: Christian Risi <75698846+CnF-Gris@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:57:56 +0000 Subject: [PATCH] V0.6.5 Arroyo Toad --- .environment/.env.example | 8 +- .npmrc | 2 + .vscode/launch.json | 2 + deno.json | 7 +- deno.lock | 424 ++++++++++++++++++++++- drizzle.config.ts | 26 ++ drizzle/0000_wide_darkhawk.sql | 13 + drizzle/meta/0000_snapshot.json | 100 ++++++ drizzle/meta/_journal.json | 13 + main.ts | 5 +- main_test.ts | 3 +- src/db/db.ts | 70 ++++ src/db/relations.ts | 3 + src/db/schema/iot-sensors-data.schema.ts | 25 ++ src/routes/Api.ts | 7 + src/routes/v1/iot-data.ts | 53 +++ 16 files changed, 754 insertions(+), 7 deletions(-) create mode 100644 .npmrc create mode 100644 drizzle.config.ts create mode 100644 drizzle/0000_wide_darkhawk.sql create mode 100644 drizzle/meta/0000_snapshot.json create mode 100644 drizzle/meta/_journal.json create mode 100644 src/db/db.ts create mode 100644 src/db/relations.ts create mode 100644 src/db/schema/iot-sensors-data.schema.ts create mode 100644 src/routes/Api.ts create mode 100644 src/routes/v1/iot-data.ts diff --git a/.environment/.env.example b/.environment/.env.example index 7768a72..a9383a4 100644 --- a/.environment/.env.example +++ b/.environment/.env.example @@ -1,2 +1,6 @@ -DB_PASSWORD=abcdefg1234 -DB_USER=Admin \ No newline at end of file +DB_PASSWORD=abcd1234 +DB_USER=Admin +DB_HOST=iot-data-db.internal +DB=SAPD +DB_PORT=5432 +PUBLIC_KEY_DB_URL=http://public-key-db.internal/key \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..3afb67c --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +@farmtoad:registry=https://repositories.communitynotfound.work/api/packages/PoliBa-Software-Architecture/npm/ +//repositories.communitynotfound.work/api/packages/PoliBa-Software-Architecture/npm/:_authToken=${FarmToad_NPM} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index cc977bb..7956748 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,8 +12,10 @@ "cwd": "${workspaceFolder}", "env": {}, "runtimeExecutable": "/usr/bin/deno", + "envFile": "${workspaceFolder}/.environment/.env", "runtimeArgs": [ "run", + "--reload", "--unstable", "--inspect-wait", "--allow-all" diff --git a/deno.json b/deno.json index 81148c0..93c6cd4 100644 --- a/deno.json +++ b/deno.json @@ -4,6 +4,11 @@ }, "imports": { "@hono/hono": "jsr:@hono/hono@^4.6.14", - "@std/assert": "jsr:@std/assert@1" + "@std/assert": "jsr:@std/assert@1", + "@types/pg": "npm:@types/pg@^8.11.10", + "drizzle-kit": "npm:drizzle-kit@^0.30.1", + "drizzle-orm": "npm:drizzle-orm@^0.38.2", + "pg": "npm:pg@^8.13.1", + "@farmtoad/farmtoad-msg-utils": "npm:@farmtoad/farmtoad-msg-utils@^0.7.2" } } diff --git a/deno.lock b/deno.lock index 3600b62..0c2c0cc 100644 --- a/deno.lock +++ b/deno.lock @@ -3,7 +3,15 @@ "specifiers": { "jsr:@hono/hono@^4.6.14": "4.6.14", "jsr:@std/assert@1": "1.0.9", - "jsr:@std/internal@^1.0.5": "1.0.5" + "jsr:@std/internal@^1.0.5": "1.0.5", + "npm:@farmtoad/farmtoad-msg-utils@~0.7.2": "0.7.2", + "npm:@types/node@*": "22.5.4", + "npm:@types/pg@^8.11.10": "8.11.10", + "npm:drizzle-kit@*": "0.30.1_esbuild@0.19.12", + "npm:drizzle-kit@~0.30.1": "0.30.1_esbuild@0.19.12", + "npm:drizzle-orm@*": "0.38.2_@types+pg@8.11.10_pg@8.13.1", + "npm:drizzle-orm@~0.38.2": "0.38.2_@types+pg@8.11.10_pg@8.13.1", + "npm:pg@^8.13.1": "8.13.1" }, "jsr": { "@hono/hono@4.6.14": { @@ -19,10 +27,422 @@ "integrity": "54a546004f769c1ac9e025abd15a76b6671ddc9687e2313b67376125650dc7ba" } }, + "npm": { + "@deno/shim-deno-test@0.4.0": { + "integrity": "sha512-oYWcD7CpERZy/TXMTM9Tgh1HD/POHlbY9WpzmAk+5H8DohcxG415Qws8yLGlim3EaKBT2v3lJv01x4G0BosnaQ==" + }, + "@deno/shim-deno@0.16.1": { + "integrity": "sha512-s9v0kzF5bm/o9TgdwvsraHx6QNllYrXXmKzgOG2lh4LFXnVMr2gpjK/c/ve6EflQn1MqImcWmVD8HAv5ahuuZQ==", + "dependencies": [ + "@deno/shim-deno-test", + "which" + ] + }, + "@drizzle-team/brocli@0.10.2": { + "integrity": "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==" + }, + "@esbuild-kit/core-utils@3.3.2": { + "integrity": "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==", + "dependencies": [ + "esbuild@0.18.20", + "source-map-support" + ] + }, + "@esbuild-kit/esm-loader@2.6.5": { + "integrity": "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==", + "dependencies": [ + "@esbuild-kit/core-utils", + "get-tsconfig" + ] + }, + "@esbuild/aix-ppc64@0.19.12": { + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==" + }, + "@esbuild/android-arm64@0.18.20": { + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==" + }, + "@esbuild/android-arm64@0.19.12": { + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==" + }, + "@esbuild/android-arm@0.18.20": { + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==" + }, + "@esbuild/android-arm@0.19.12": { + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==" + }, + "@esbuild/android-x64@0.18.20": { + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==" + }, + "@esbuild/android-x64@0.19.12": { + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==" + }, + "@esbuild/darwin-arm64@0.18.20": { + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==" + }, + "@esbuild/darwin-arm64@0.19.12": { + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==" + }, + "@esbuild/darwin-x64@0.18.20": { + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==" + }, + "@esbuild/darwin-x64@0.19.12": { + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==" + }, + "@esbuild/freebsd-arm64@0.18.20": { + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==" + }, + "@esbuild/freebsd-arm64@0.19.12": { + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==" + }, + "@esbuild/freebsd-x64@0.18.20": { + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==" + }, + "@esbuild/freebsd-x64@0.19.12": { + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==" + }, + "@esbuild/linux-arm64@0.18.20": { + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==" + }, + "@esbuild/linux-arm64@0.19.12": { + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==" + }, + "@esbuild/linux-arm@0.18.20": { + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==" + }, + "@esbuild/linux-arm@0.19.12": { + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==" + }, + "@esbuild/linux-ia32@0.18.20": { + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==" + }, + "@esbuild/linux-ia32@0.19.12": { + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==" + }, + "@esbuild/linux-loong64@0.18.20": { + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==" + }, + "@esbuild/linux-loong64@0.19.12": { + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==" + }, + "@esbuild/linux-mips64el@0.18.20": { + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==" + }, + "@esbuild/linux-mips64el@0.19.12": { + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==" + }, + "@esbuild/linux-ppc64@0.18.20": { + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==" + }, + "@esbuild/linux-ppc64@0.19.12": { + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==" + }, + "@esbuild/linux-riscv64@0.18.20": { + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==" + }, + "@esbuild/linux-riscv64@0.19.12": { + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==" + }, + "@esbuild/linux-s390x@0.18.20": { + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==" + }, + "@esbuild/linux-s390x@0.19.12": { + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==" + }, + "@esbuild/linux-x64@0.18.20": { + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==" + }, + "@esbuild/linux-x64@0.19.12": { + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==" + }, + "@esbuild/netbsd-x64@0.18.20": { + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==" + }, + "@esbuild/netbsd-x64@0.19.12": { + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==" + }, + "@esbuild/openbsd-x64@0.18.20": { + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==" + }, + "@esbuild/openbsd-x64@0.19.12": { + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==" + }, + "@esbuild/sunos-x64@0.18.20": { + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==" + }, + "@esbuild/sunos-x64@0.19.12": { + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==" + }, + "@esbuild/win32-arm64@0.18.20": { + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==" + }, + "@esbuild/win32-arm64@0.19.12": { + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==" + }, + "@esbuild/win32-ia32@0.18.20": { + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==" + }, + "@esbuild/win32-ia32@0.19.12": { + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==" + }, + "@esbuild/win32-x64@0.18.20": { + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==" + }, + "@esbuild/win32-x64@0.19.12": { + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==" + }, + "@farmtoad/farmtoad-msg-utils@0.7.2": { + "integrity": "sha512-NmwDwSqPP91cM8KzPAhZt/0NbUbuv91o8DhDgO/qiffDBkuw1e6sF5VlLUR9WyKQFQzb+lV2eIQrJPvbvu8HQQ==", + "dependencies": [ + "@deno/shim-deno" + ] + }, + "@types/node@22.5.4": { + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dependencies": [ + "undici-types" + ] + }, + "@types/pg@8.11.10": { + "integrity": "sha512-LczQUW4dbOQzsH2RQ5qoeJ6qJPdrcM/DcMLoqWQkMLMsq83J5lAX3LXjdkWdpscFy67JSOWDnh7Ny/sPFykmkg==", + "dependencies": [ + "@types/node", + "pg-protocol", + "pg-types@4.0.2" + ] + }, + "buffer-from@1.1.2": { + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "debug@4.4.0": { + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dependencies": [ + "ms" + ] + }, + "drizzle-kit@0.30.1_esbuild@0.19.12": { + "integrity": "sha512-HmA/NeewvHywhJ2ENXD3KvOuM/+K2dGLJfxVfIHsGwaqKICJnS+Ke2L6UcSrSrtMJLJaT0Im1Qv4TFXfaZShyw==", + "dependencies": [ + "@drizzle-team/brocli", + "@esbuild-kit/esm-loader", + "esbuild@0.19.12", + "esbuild-register" + ] + }, + "drizzle-orm@0.38.2_@types+pg@8.11.10_pg@8.13.1": { + "integrity": "sha512-eCE3yPRAskLo1WpM9OHpFaM70tBEDsWhwR/0M3CKyztAXKR9Qs3asZlcJOEliIcUSg8GuwrlY0dmYDgmm6y5GQ==", + "dependencies": [ + "@types/pg", + "pg" + ] + }, + "esbuild-register@3.6.0_esbuild@0.19.12": { + "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", + "dependencies": [ + "debug", + "esbuild@0.19.12" + ] + }, + "esbuild@0.18.20": { + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dependencies": [ + "@esbuild/android-arm@0.18.20", + "@esbuild/android-arm64@0.18.20", + "@esbuild/android-x64@0.18.20", + "@esbuild/darwin-arm64@0.18.20", + "@esbuild/darwin-x64@0.18.20", + "@esbuild/freebsd-arm64@0.18.20", + "@esbuild/freebsd-x64@0.18.20", + "@esbuild/linux-arm@0.18.20", + "@esbuild/linux-arm64@0.18.20", + "@esbuild/linux-ia32@0.18.20", + "@esbuild/linux-loong64@0.18.20", + "@esbuild/linux-mips64el@0.18.20", + "@esbuild/linux-ppc64@0.18.20", + "@esbuild/linux-riscv64@0.18.20", + "@esbuild/linux-s390x@0.18.20", + "@esbuild/linux-x64@0.18.20", + "@esbuild/netbsd-x64@0.18.20", + "@esbuild/openbsd-x64@0.18.20", + "@esbuild/sunos-x64@0.18.20", + "@esbuild/win32-arm64@0.18.20", + "@esbuild/win32-ia32@0.18.20", + "@esbuild/win32-x64@0.18.20" + ] + }, + "esbuild@0.19.12": { + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "dependencies": [ + "@esbuild/aix-ppc64", + "@esbuild/android-arm@0.19.12", + "@esbuild/android-arm64@0.19.12", + "@esbuild/android-x64@0.19.12", + "@esbuild/darwin-arm64@0.19.12", + "@esbuild/darwin-x64@0.19.12", + "@esbuild/freebsd-arm64@0.19.12", + "@esbuild/freebsd-x64@0.19.12", + "@esbuild/linux-arm@0.19.12", + "@esbuild/linux-arm64@0.19.12", + "@esbuild/linux-ia32@0.19.12", + "@esbuild/linux-loong64@0.19.12", + "@esbuild/linux-mips64el@0.19.12", + "@esbuild/linux-ppc64@0.19.12", + "@esbuild/linux-riscv64@0.19.12", + "@esbuild/linux-s390x@0.19.12", + "@esbuild/linux-x64@0.19.12", + "@esbuild/netbsd-x64@0.19.12", + "@esbuild/openbsd-x64@0.19.12", + "@esbuild/sunos-x64@0.19.12", + "@esbuild/win32-arm64@0.19.12", + "@esbuild/win32-ia32@0.19.12", + "@esbuild/win32-x64@0.19.12" + ] + }, + "get-tsconfig@4.8.1": { + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", + "dependencies": [ + "resolve-pkg-maps" + ] + }, + "isexe@2.0.0": { + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "ms@2.1.3": { + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "obuf@1.1.2": { + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "pg-cloudflare@1.1.1": { + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==" + }, + "pg-connection-string@2.7.0": { + "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==" + }, + "pg-int8@1.0.1": { + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-numeric@1.0.2": { + "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==" + }, + "pg-pool@3.7.0_pg@8.13.1": { + "integrity": "sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==", + "dependencies": [ + "pg" + ] + }, + "pg-protocol@1.7.0": { + "integrity": "sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==" + }, + "pg-types@2.2.0": { + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": [ + "pg-int8", + "postgres-array@2.0.0", + "postgres-bytea@1.0.0", + "postgres-date@1.0.7", + "postgres-interval@1.2.0" + ] + }, + "pg-types@4.0.2": { + "integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==", + "dependencies": [ + "pg-int8", + "pg-numeric", + "postgres-array@3.0.2", + "postgres-bytea@3.0.0", + "postgres-date@2.1.0", + "postgres-interval@3.0.0", + "postgres-range" + ] + }, + "pg@8.13.1": { + "integrity": "sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==", + "dependencies": [ + "pg-cloudflare", + "pg-connection-string", + "pg-pool", + "pg-protocol", + "pg-types@2.2.0", + "pgpass" + ] + }, + "pgpass@1.0.5": { + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": [ + "split2" + ] + }, + "postgres-array@2.0.0": { + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-array@3.0.2": { + "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==" + }, + "postgres-bytea@1.0.0": { + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" + }, + "postgres-bytea@3.0.0": { + "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", + "dependencies": [ + "obuf" + ] + }, + "postgres-date@1.0.7": { + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-date@2.1.0": { + "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==" + }, + "postgres-interval@1.2.0": { + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": [ + "xtend" + ] + }, + "postgres-interval@3.0.0": { + "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==" + }, + "postgres-range@1.1.4": { + "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==" + }, + "resolve-pkg-maps@1.0.0": { + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==" + }, + "source-map-support@0.5.21": { + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": [ + "buffer-from", + "source-map" + ] + }, + "source-map@0.6.1": { + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "split2@4.2.0": { + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" + }, + "undici-types@6.19.8": { + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" + }, + "which@2.0.2": { + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": [ + "isexe" + ] + }, + "xtend@4.0.2": { + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + } + }, "workspace": { "dependencies": [ "jsr:@hono/hono@^4.6.14", - "jsr:@std/assert@1" + "jsr:@std/assert@1", + "npm:@farmtoad/farmtoad-msg-utils@~0.7.2", + "npm:@types/pg@^8.11.10", + "npm:drizzle-kit@~0.30.1", + "npm:drizzle-orm@~0.38.2", + "npm:pg@^8.13.1" ] } } diff --git a/drizzle.config.ts b/drizzle.config.ts new file mode 100644 index 0000000..d6791ec --- /dev/null +++ b/drizzle.config.ts @@ -0,0 +1,26 @@ +import { defineConfig } from "drizzle-kit"; + +function createConnectionString( + user: string, + password: string, + host: string, + port: string | number, + db: string +) { + return `postgresql://${user}:${password}@${host}:${port}/${db}` +} + +export default defineConfig({ + out: "./drizzle", + schema: "./src/db/schema/*", + dialect: "postgresql", + dbCredentials: { + url: createConnectionString( + Deno.env.get("DB_USER")!, + Deno.env.get("DB_PASSWORD")!, + Deno.env.get("DB_HOST")!, + Deno.env.get("DB_PORT")!, + Deno.env.get("DB")! + ) + } +}); \ No newline at end of file diff --git a/drizzle/0000_wide_darkhawk.sql b/drizzle/0000_wide_darkhawk.sql new file mode 100644 index 0000000..f89df6a --- /dev/null +++ b/drizzle/0000_wide_darkhawk.sql @@ -0,0 +1,13 @@ +CREATE TABLE "IoT-Sensors-Data" ( + "id" serial PRIMARY KEY NOT NULL, + "deviceType" integer NOT NULL, + "deviceID" integer NOT NULL, + "timestamp" date NOT NULL, + "xCoordinates" integer NOT NULL, + "yCoordinates" integer NOT NULL, + "zCoordinates" integer NOT NULL, + "dataType" text NOT NULL, + "mean_value" real NOT NULL, + "std_value" real NOT NULL, + CONSTRAINT "IoT-Sensors-Data_id_unique" UNIQUE("id") +); diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json new file mode 100644 index 0000000..8e1cc1c --- /dev/null +++ b/drizzle/meta/0000_snapshot.json @@ -0,0 +1,100 @@ +{ + "id": "92bb7aaa-a1a9-42a6-9800-74a7d19fa67b", + "prevId": "00000000-0000-0000-0000-000000000000", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.IoT-Sensors-Data": { + "name": "IoT-Sensors-Data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "deviceType": { + "name": "deviceType", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "deviceID": { + "name": "deviceID", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "timestamp": { + "name": "timestamp", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "xCoordinates": { + "name": "xCoordinates", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "yCoordinates": { + "name": "yCoordinates", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "zCoordinates": { + "name": "zCoordinates", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "dataType": { + "name": "dataType", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mean_value": { + "name": "mean_value", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "std_value": { + "name": "std_value", + "type": "real", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "IoT-Sensors-Data_id_unique": { + "name": "IoT-Sensors-Data_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json new file mode 100644 index 0000000..7c77469 --- /dev/null +++ b/drizzle/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "7", + "dialect": "postgresql", + "entries": [ + { + "idx": 0, + "version": "7", + "when": 1734302951810, + "tag": "0000_wide_darkhawk", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/main.ts b/main.ts index 67a97db..7ce1cbf 100644 --- a/main.ts +++ b/main.ts @@ -1,7 +1,10 @@ import { Hono } from '@hono/hono' +import { iotData } from "./src/routes/Api.ts"; const app = new Hono() app.get('/', (c) => c.text('Hello Deno!')) -Deno.serve(app.fetch) \ No newline at end of file +app.route("/", iotData) + +Deno.serve({port:80}, app.fetch) \ No newline at end of file diff --git a/main_test.ts b/main_test.ts index 0ff7da6..d6b163f 100644 --- a/main_test.ts +++ b/main_test.ts @@ -1,6 +1,7 @@ import { assertEquals } from "@std/assert"; + Deno.test(function addTest() { - + }); diff --git a/src/db/db.ts b/src/db/db.ts new file mode 100644 index 0000000..8f405e7 --- /dev/null +++ b/src/db/db.ts @@ -0,0 +1,70 @@ +import { drizzle } from "drizzle-orm/node-postgres"; +import { iotData as iotDataSchema } from "./schema/iot-sensors-data.schema.ts"; +import pg from "pg"; +import * as pgCore from "drizzle-orm/pg-core"; +import { eq } from "drizzle-orm/expressions"; + +// Use pg driver. +const { Pool } = pg; + +function createConnectionString( + user: string, + password: string, + host: string, + port: string | number, + db: string +) { + return `postgresql://${user}:${password}@${host}:${port}/${db}` +} + +// Instantiate Drizzle client with pg driver and schema. +export const db = drizzle({ + client: new Pool({ + connectionString: createConnectionString( + Deno.env.get("DB_USER")!, + Deno.env.get("DB_PASSWORD")!, + Deno.env.get("DB_HOST")!, + Deno.env.get("DB_PORT")!, + Deno.env.get("DB")! + ), + }), + schema: { iotDataSchema }, +}); + +export type IoTDatum = typeof iotDataSchema.$inferInsert + + +export async function insertIoTDatum(iotDatum: typeof iotDataSchema.$inferInsert) { + return await db.insert(iotDataSchema).values(iotDatum) +} + + +export async function findIoTDatumByID(datumID: number) { + return await db.select().from(iotDataSchema).where( + eq(iotDataSchema.id, datumID) + ) +} + +// UGLY: Downcasting from bigint to number +export async function findIoTDatumByDeviceID(deviceID: bigint) { + const _deviceID: number = Number(deviceID) + return await db.select().from(iotDataSchema).where( + eq(iotDataSchema.deviceID, _deviceID) + ) +} + +export async function getPage(offset: number = 0, numberOfResults: number = 100) { + return await db + .select() + .from(iotDataSchema) + .orderBy(iotDataSchema.id) + .limit(numberOfResults) + .offset(offset) +} + + +export async function deleteIoTDatumByID(datumID: number) { + return await db.delete(iotDataSchema).where( + eq(iotDataSchema.id, datumID) + ) +} \ No newline at end of file diff --git a/src/db/relations.ts b/src/db/relations.ts new file mode 100644 index 0000000..80768e2 --- /dev/null +++ b/src/db/relations.ts @@ -0,0 +1,3 @@ +import { relations } from "drizzle-orm/relations"; +import { } from "./schema"; + diff --git a/src/db/schema/iot-sensors-data.schema.ts b/src/db/schema/iot-sensors-data.schema.ts new file mode 100644 index 0000000..16522b8 --- /dev/null +++ b/src/db/schema/iot-sensors-data.schema.ts @@ -0,0 +1,25 @@ +import * as pgCore from "drizzle-orm/pg-core"; + +// UGLY +// UGLY: These are mockup values, but ideally, for +// UGLY: our project requirements, we should opt to use decimal +// UGLY: instead of integer and decimal serial or similar for serial. +// UGLY: +// UGLY: So these are just TOY VALUES +// UGLY: + + +export const iotData = pgCore.pgTable("IoT-Sensors-Data", { + id: pgCore.serial().primaryKey().notNull().unique(), + deviceType: pgCore.integer().notNull(), + deviceID: pgCore.integer().notNull(), + timestamp: pgCore.date().notNull(), + xCoordinates: pgCore.integer().notNull(), + yCoordinates: pgCore.integer().notNull(), + zCoordinates: pgCore.integer().notNull(), + dataType: pgCore.text().notNull(), + mean_value: pgCore.real().notNull(), + std_value: pgCore.real().notNull() +}); + +// We could in theory add the binary message, however this is just a demo \ No newline at end of file diff --git a/src/routes/Api.ts b/src/routes/Api.ts new file mode 100644 index 0000000..3dac6b7 --- /dev/null +++ b/src/routes/Api.ts @@ -0,0 +1,7 @@ +import { Hono } from "@hono/hono"; +import { iotDataV1 } from "./v1/iot-data.ts"; + +export const iotData = new Hono().basePath("/iot-data/api") + +iotData.route("/", iotDataV1) + diff --git a/src/routes/v1/iot-data.ts b/src/routes/v1/iot-data.ts new file mode 100644 index 0000000..afb0c87 --- /dev/null +++ b/src/routes/v1/iot-data.ts @@ -0,0 +1,53 @@ +import { Hono } from "@hono/hono"; +import { getPage, insertIoTDatum, IoTDatum } from "../../db/db.ts"; +import { deserializerV1, DeviceType, pemString2_P256key} from "@farmtoad/farmtoad-msg-utils"; +import { webcrypto } from "node:crypto"; +import { iotData } from "../../db/schema/iot-sensors-data.schema.ts"; + +export const iotDataV1 = new Hono().basePath("/v1") + +iotDataV1.get("/data", async (context) => { + const { strOffset, strNumberOfData } = context.req.query() + + const offset = Number(strOffset) + const numberOfData = Number(strNumberOfData) + + const page = await getPage(offset, numberOfData) + + return context.json({ + page: page + }) + +}) + +// TODO: have a post to insert all data inside here +iotDataV1.post("/data", async (context) => { + const KEY_DB_URL = Deno.env.get("PUBLIC_KEY_DB_URL")! + const data = await context.req.arrayBuffer() + const message = await deserializerV1(data , async (deviceType: DeviceType, deviceID: bigint) => { + const res = await fetch(`${KEY_DB_URL}/${deviceID}`) + const json = await res.json() + return await pemString2_P256key(json.publicKey) + }) + + // FIXME: we forget to set Fields as a map, instead of an array + // FIXME: not a big of a deal since we know the message structure + const datum : IoTDatum = { + deviceType: message.deviceType, + deviceID: Number(message.deviceID), + timestamp: new Date(message.timestamp).toISOString(), + xCoordinates: Number(message.location.x), + yCoordinates: Number(message.location.y), + zCoordinates: Number(message.location.z), + dataType: new TextDecoder().decode(message.fields[0].value), + mean_value: Number( + new TextDecoder().decode(message.fields[1].value) + ), + std_value: Number( + new TextDecoder().decode(message.fields[2].value) + ), + } + + insertIoTDatum(datum) +}) +