Compare commits
No commits in common. "43feec227c05c2cc5a6261a874d62c4c6e2c866e" and "ad003c4ae053f2a31a09c6608aaa76d752602b32" have entirely different histories.
43feec227c
...
ad003c4ae0
10 changed files with 142 additions and 654 deletions
343
deno.lock
generated
343
deno.lock
generated
|
@ -1,338 +1,10 @@
|
|||
{
|
||||
"version": "3",
|
||||
"packages": {
|
||||
"specifiers": {
|
||||
"npm:@deepkit/type@1.0.1-alpha.97": "npm:@deepkit/type@1.0.1-alpha.97_@deepkit+core@1.0.1-alpha.108",
|
||||
"npm:@effect/schema@0.36.5": "npm:@effect/schema@0.36.5_@effect+data@0.18.7_@effect+io@0.40.3__@effect+data@0.18.7",
|
||||
"npm:@ovh-api/api": "npm:@ovh-api/api@4.1.3",
|
||||
"npm:@ovh-api/domain": "npm:@ovh-api/domain@4.0.3",
|
||||
"npm:@sinclair/typebox@0.31.17": "npm:@sinclair/typebox@0.31.17",
|
||||
"npm:ajv@8.12.0": "npm:ajv@8.12.0",
|
||||
"npm:arktype@1.0.21-alpha": "npm:arktype@1.0.21-alpha",
|
||||
"npm:io-ts@2.2.20": "npm:io-ts@2.2.20_fp-ts@2.16.1",
|
||||
"npm:joi@17.10.2": "npm:joi@17.10.2",
|
||||
"npm:ovh-es": "npm:ovh-es@1.7.0",
|
||||
"npm:ow@0.28.2": "npm:ow@0.28.2",
|
||||
"npm:runtypes@6.7.0": "npm:runtypes@6.7.0",
|
||||
"npm:superstruct@1.0.3": "npm:superstruct@1.0.3",
|
||||
"npm:yup@1.3.2": "npm:yup@1.3.2"
|
||||
},
|
||||
"npm": {
|
||||
"@deepkit/core@1.0.1-alpha.108": {
|
||||
"integrity": "sha512-4nN9qL7OSG8kAvhI4aNVGSADgLK7ZPetISfTq7LGSWZJGnT4hGi+/Dxd2bW3KYrUZ4NRP+e/N3IUaQBkSAJ6Pw==",
|
||||
"dependencies": {
|
||||
"dot-prop": "dot-prop@5.3.0",
|
||||
"to-fast-properties": "to-fast-properties@3.0.1"
|
||||
}
|
||||
},
|
||||
"@deepkit/type-spec@1.0.1-alpha.108": {
|
||||
"integrity": "sha512-OIJsZ0nZKybaKrzrY7WpkIlDXm88wE8N5G5cu+FL3snZx/drzF5FxmbRP2omLGRRDb68+o/vTni26sUbBtWOBw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"@deepkit/type@1.0.1-alpha.97_@deepkit+core@1.0.1-alpha.108": {
|
||||
"integrity": "sha512-fnMrhMVYANyZ8zrKEj7KnJMTl2WhXKza9dh9s0Mtgcowd73YSJyEdvFkBKcabmHbvlbHFkAHv8KAvYifvWbGvw==",
|
||||
"dependencies": {
|
||||
"@deepkit/core": "@deepkit/core@1.0.1-alpha.108",
|
||||
"@deepkit/type-spec": "@deepkit/type-spec@1.0.1-alpha.108",
|
||||
"@types/uuid": "@types/uuid@8.3.4",
|
||||
"buffer": "buffer@5.7.1",
|
||||
"uuid": "uuid@8.3.2"
|
||||
}
|
||||
},
|
||||
"@effect/data@0.18.7": {
|
||||
"integrity": "sha512-r7C9VjavmG85wb5BOvcbbKGioPJCoBAFsJVOUNWlxZBRIU+l68ENpsyzCkWsU7dP4teAztjBZ89O3hVhBX0Huw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"@effect/io@0.40.3_@effect+data@0.18.7": {
|
||||
"integrity": "sha512-bnHBFq1XzXn94x2w5FcXZz3MbY7N3YrhiI2CrncJr3WcGRDc2rCYIpPupw0JQGFcJsoopTj1BNfBuBR5s4/RyA==",
|
||||
"dependencies": {
|
||||
"@effect/data": "@effect/data@0.18.7"
|
||||
}
|
||||
},
|
||||
"@effect/schema@0.36.5_@effect+data@0.18.7_@effect+io@0.40.3__@effect+data@0.18.7": {
|
||||
"integrity": "sha512-E8KZ17DqZJl7E/eEVTkxb2NEv6vYhab79HugHi10krd2Gm3vOJvWs+nRgtPhI+0dvkXVxzCcY8bLfkND2F0rBg==",
|
||||
"dependencies": {
|
||||
"@effect/data": "@effect/data@0.18.7",
|
||||
"@effect/io": "@effect/io@0.40.3_@effect+data@0.18.7",
|
||||
"fast-check": "fast-check@3.14.0"
|
||||
}
|
||||
},
|
||||
"@hapi/hoek@9.3.0": {
|
||||
"integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"@hapi/topo@5.1.0": {
|
||||
"integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==",
|
||||
"dependencies": {
|
||||
"@hapi/hoek": "@hapi/hoek@9.3.0"
|
||||
}
|
||||
},
|
||||
"@ovh-api/api@4.1.3": {
|
||||
"integrity": "sha512-gRnlqLEolPj2thBHt7tlM0z1tPNc86PSmOy3jkmOr46hAY+eHI/mGlTInIAJknc9iDSqZ9eIVzUiNngtjysYAw==",
|
||||
"dependencies": {
|
||||
"@ovh-api/common": "@ovh-api/common@4.0.2",
|
||||
"open": "open@8.4.2"
|
||||
}
|
||||
},
|
||||
"@ovh-api/common@4.0.2": {
|
||||
"integrity": "sha512-9PKJjtq7l2mP1t6Ta+cEYZKF3UkHtR1P6f5xvH+M78Hgj7HMwX2vxByuf5FkipOeb3Elfq8ASwZxSiP5+wMP7g==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"@ovh-api/domain@4.0.3": {
|
||||
"integrity": "sha512-ARUCOicVekcXmXAUV03aFqXGoHpYow3jyvdqq8e7k3ftXtvkoR1UQXX4rWGXdWgxW7rA7ooDWcU+vGm/jYQqgQ==",
|
||||
"dependencies": {
|
||||
"@ovh-api/common": "@ovh-api/common@4.0.2"
|
||||
}
|
||||
},
|
||||
"@sideway/address@4.1.4": {
|
||||
"integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==",
|
||||
"dependencies": {
|
||||
"@hapi/hoek": "@hapi/hoek@9.3.0"
|
||||
}
|
||||
},
|
||||
"@sideway/formula@3.0.1": {
|
||||
"integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"@sideway/pinpoint@2.0.0": {
|
||||
"integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"@sinclair/typebox@0.31.17": {
|
||||
"integrity": "sha512-GVYVHHOGINx+DT2DwjXoCQO0mRpztYKyb3d48tucuqhjhHpQYGp7Xx7dhhQGzILx/beuBrzfITMC7/5X7fw+UA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"@sindresorhus/is@4.6.0": {
|
||||
"integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"@types/uuid@8.3.4": {
|
||||
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"ajv@8.12.0": {
|
||||
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "fast-deep-equal@3.1.3",
|
||||
"json-schema-traverse": "json-schema-traverse@1.0.0",
|
||||
"require-from-string": "require-from-string@2.0.2",
|
||||
"uri-js": "uri-js@4.4.1"
|
||||
}
|
||||
},
|
||||
"arktype@1.0.21-alpha": {
|
||||
"integrity": "sha512-XQBoepICSrwDXYlh7gqcrKWEbWTSebToIoTimi9CxVLLlxNWt/YXNrKrSITr/T9jke+TIag1tUcIum/90EQNpg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"base64-js@1.5.1": {
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"buffer@5.7.1": {
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"dependencies": {
|
||||
"base64-js": "base64-js@1.5.1",
|
||||
"ieee754": "ieee754@1.2.1"
|
||||
}
|
||||
},
|
||||
"callsites@3.1.0": {
|
||||
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"debug@2.6.9": {
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dependencies": {
|
||||
"ms": "ms@2.0.0"
|
||||
}
|
||||
},
|
||||
"define-lazy-prop@2.0.0": {
|
||||
"integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"dot-prop@5.3.0": {
|
||||
"integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
|
||||
"dependencies": {
|
||||
"is-obj": "is-obj@2.0.0"
|
||||
}
|
||||
},
|
||||
"dot-prop@6.0.1": {
|
||||
"integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==",
|
||||
"dependencies": {
|
||||
"is-obj": "is-obj@2.0.0"
|
||||
}
|
||||
},
|
||||
"fast-check@3.14.0": {
|
||||
"integrity": "sha512-9Z0zqASzDNjXBox/ileV/fd+4P+V/f3o4shM6QawvcdLFh8yjPG4h5BrHUZ8yzY6amKGDTAmRMyb/JZqe+dCgw==",
|
||||
"dependencies": {
|
||||
"pure-rand": "pure-rand@6.0.4"
|
||||
}
|
||||
},
|
||||
"fast-deep-equal@3.1.3": {
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"fp-ts@2.16.1": {
|
||||
"integrity": "sha512-by7U5W8dkIzcvDofUcO42yl9JbnHTEDBrzu3pt5fKT+Z4Oy85I21K80EYJYdjQGC2qum4Vo55Ag57iiIK4FYuA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"ieee754@1.2.1": {
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"io-ts@2.2.20_fp-ts@2.16.1": {
|
||||
"integrity": "sha512-Rq2BsYmtwS5vVttie4rqrOCIfHCS9TgpRLFpKQCM1wZBBRY9nWVGmEvm2FnDbSE2un1UE39DvFpTR5UL47YDcA==",
|
||||
"dependencies": {
|
||||
"fp-ts": "fp-ts@2.16.1"
|
||||
}
|
||||
},
|
||||
"is-docker@2.2.1": {
|
||||
"integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"is-obj@2.0.0": {
|
||||
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"is-wsl@2.2.0": {
|
||||
"integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
|
||||
"dependencies": {
|
||||
"is-docker": "is-docker@2.2.1"
|
||||
}
|
||||
},
|
||||
"joi@17.10.2": {
|
||||
"integrity": "sha512-hcVhjBxRNW/is3nNLdGLIjkgXetkeGc2wyhydhz8KumG23Aerk4HPjU5zaPAMRqXQFc0xNqXTC7+zQjxr0GlKA==",
|
||||
"dependencies": {
|
||||
"@hapi/hoek": "@hapi/hoek@9.3.0",
|
||||
"@hapi/topo": "@hapi/topo@5.1.0",
|
||||
"@sideway/address": "@sideway/address@4.1.4",
|
||||
"@sideway/formula": "@sideway/formula@3.0.1",
|
||||
"@sideway/pinpoint": "@sideway/pinpoint@2.0.0"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse@1.0.0": {
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"lodash.isequal@4.5.0": {
|
||||
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"mout@1.2.4": {
|
||||
"integrity": "sha512-mZb9uOruMWgn/fw28DG4/yE3Kehfk1zKCLhuDU2O3vlKdnBBr4XaOCqVTflJ5aODavGUPqFHZgrFX3NJVuxGhQ==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"ms@2.0.0": {
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"nyks@6.10.0": {
|
||||
"integrity": "sha512-Y65Kzo+A9b+BzsGBSfpjdm1a496sH564gHZ1anw8yNA+Ki9u2KC4EJuDQCSTbNliE1g76YsxAs6SWKXhZDsbJA==",
|
||||
"dependencies": {
|
||||
"mout": "mout@1.2.4"
|
||||
}
|
||||
},
|
||||
"open@8.4.2": {
|
||||
"integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
|
||||
"dependencies": {
|
||||
"define-lazy-prop": "define-lazy-prop@2.0.0",
|
||||
"is-docker": "is-docker@2.2.1",
|
||||
"is-wsl": "is-wsl@2.2.0"
|
||||
}
|
||||
},
|
||||
"ovh-es@1.7.0": {
|
||||
"integrity": "sha512-om96fYG7JpCfDyegVynDpkmIixMsqPkDb8V3Mz7i+7sC9NPxNwe9icRrBzexcDvMstJH0t7QnesRHDPuA2hMwg==",
|
||||
"dependencies": {
|
||||
"debug": "debug@2.6.9",
|
||||
"mout": "mout@1.2.4",
|
||||
"nyks": "nyks@6.10.0"
|
||||
}
|
||||
},
|
||||
"ow@0.28.2": {
|
||||
"integrity": "sha512-dD4UpyBh/9m4X2NVjA+73/ZPBRF+uF4zIMFvvQsabMiEK8x41L3rQ8EENOi35kyyoaJwNxEeJcP6Fj1H4U409Q==",
|
||||
"dependencies": {
|
||||
"@sindresorhus/is": "@sindresorhus/is@4.6.0",
|
||||
"callsites": "callsites@3.1.0",
|
||||
"dot-prop": "dot-prop@6.0.1",
|
||||
"lodash.isequal": "lodash.isequal@4.5.0",
|
||||
"vali-date": "vali-date@1.0.0"
|
||||
}
|
||||
},
|
||||
"property-expr@2.0.6": {
|
||||
"integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"punycode@2.3.0": {
|
||||
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"pure-rand@6.0.4": {
|
||||
"integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"require-from-string@2.0.2": {
|
||||
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"runtypes@6.7.0": {
|
||||
"integrity": "sha512-3TLdfFX8YHNFOhwHrSJza6uxVBmBrEjnNQlNXvXCdItS0Pdskfg5vVXUTWIN+Y23QR09jWpSl99UHkA83m4uWA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"superstruct@1.0.3": {
|
||||
"integrity": "sha512-8iTn3oSS8nRGn+C2pgXSKPI3jmpm6FExNazNpjvqS6ZUJQCej3PUXEKM8NjHBOs54ExM+LPW/FBRhymrdcCiSg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"tiny-case@1.0.3": {
|
||||
"integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"to-fast-properties@3.0.1": {
|
||||
"integrity": "sha512-/wtNi1tW1F3nf0OL6AqVxGw9Tr1ET70InMhJuVxPwFdGqparF0nQ4UWGLf2DsoI2bFDtthlBnALncZpUzOnsUw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"toposort@2.0.2": {
|
||||
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"type-fest@2.19.0": {
|
||||
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"uri-js@4.4.1": {
|
||||
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
||||
"dependencies": {
|
||||
"punycode": "punycode@2.3.0"
|
||||
}
|
||||
},
|
||||
"uuid@8.3.2": {
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"vali-date@1.0.0": {
|
||||
"integrity": "sha512-sgECfZthyaCKW10N0fm27cg8HYTFK5qMWgypqkXMQ4Wbl/zZKx7xZICgcoxIIE+WFAP/MBL2EFwC/YvLxw3Zeg==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"yup@1.3.2": {
|
||||
"integrity": "sha512-6KCM971iQtJ+/KUaHdrhVr2LDkfhBtFPRnsG1P8F4q3uUVQ2RfEM9xekpha9aA4GXWJevjM10eDcPQ1FfWlmaQ==",
|
||||
"dependencies": {
|
||||
"property-expr": "property-expr@2.0.6",
|
||||
"tiny-case": "tiny-case@1.0.3",
|
||||
"toposort": "toposort@2.0.2",
|
||||
"type-fest": "type-fest@2.19.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"redirects": {
|
||||
"https://deno.land/x/typeschema/mod.ts": "https://deno.land/x/typeschema@v0.12.1/mod.ts",
|
||||
"https://deno.land/x/validasaur/mod.ts": "https://deno.land/x/validasaur@v0.15.0/mod.ts",
|
||||
"https://deno.land/x/zod/mod.ts": "https://deno.land/x/zod@v3.22.4/mod.ts"
|
||||
},
|
||||
"remote": {
|
||||
"https://deno.land/std@0.208.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee",
|
||||
"https://deno.land/std@0.208.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56",
|
||||
"https://deno.land/std@0.208.0/bytes/concat.ts": "d3d420badeb4f26a0f2f3ce343725f937326aff1b4634b25341b12b27353aac4",
|
||||
"https://deno.land/std@0.208.0/bytes/copy.ts": "939d89e302a9761dcf1d9c937c7711174ed74c59eef40a1e4569a05c9de88219",
|
||||
"https://deno.land/std@0.208.0/encoding/_util.ts": "f368920189c4fe6592ab2e93bd7ded8f3065b84f95cd3e036a4a10a75649dcba",
|
||||
"https://deno.land/std@0.208.0/encoding/hex.ts": "a384101d02cd87036c708f540825feb5b073c8527a00d635e48b2e69c992a5f9",
|
||||
"https://deno.land/std@0.208.0/io/buffer.ts": "11acaeae3dc0e491a335d82915e09e9f8afd53ecb82562515e5951e78f69b076",
|
||||
"https://deno.land/std@0.208.0/path/_common/assert_path.ts": "061e4d093d4ba5aebceb2c4da3318bfe3289e868570e9d3a8e327d91c2958946",
|
||||
"https://deno.land/std@0.208.0/path/_common/basename.ts": "0d978ff818f339cd3b1d09dc914881f4d15617432ae519c1b8fdc09ff8d3789a",
|
||||
|
@ -436,19 +108,6 @@
|
|||
"https://deno.land/std@0.208.0/streams/writable_stream_from_writer.ts": "057bdfc6c08e34a8a86e2d61efe7354a8a0976260cd1437de8b7e64bcefaa9b9",
|
||||
"https://deno.land/std@0.208.0/streams/write_all.ts": "8fc9525c16eb60eb851274d4693ecd35c2177620239fbdfa8f5aacb32702f2cb",
|
||||
"https://deno.land/std@0.208.0/streams/writer_from_stream_writer.ts": "71d7a26f2a2b955794a7318856ad64d9eade36467d930b40698d3d5bfb0ce3b4",
|
||||
"https://deno.land/std@0.208.0/streams/zip_readable_streams.ts": "721c5bce8862c8225e60995b2d61c7b1b1d5b5178b60d303a01f453d5c26bb62",
|
||||
"https://deno.land/x/zod@v3.22.4/ZodError.ts": "4de18ff525e75a0315f2c12066b77b5c2ae18c7c15ef7df7e165d63536fdf2ea",
|
||||
"https://deno.land/x/zod@v3.22.4/errors.ts": "5285922d2be9700cc0c70c95e4858952b07ae193aa0224be3cbd5cd5567eabef",
|
||||
"https://deno.land/x/zod@v3.22.4/external.ts": "a6cfbd61e9e097d5f42f8a7ed6f92f93f51ff927d29c9fbaec04f03cbce130fe",
|
||||
"https://deno.land/x/zod@v3.22.4/helpers/enumUtil.ts": "54efc393cc9860e687d8b81ff52e980def00fa67377ad0bf8b3104f8a5bf698c",
|
||||
"https://deno.land/x/zod@v3.22.4/helpers/errorUtil.ts": "7a77328240be7b847af6de9189963bd9f79cab32bbc61502a9db4fe6683e2ea7",
|
||||
"https://deno.land/x/zod@v3.22.4/helpers/parseUtil.ts": "f791e6e65a0340d85ad37d26cd7a3ba67126cd9957eac2b7163162155283abb1",
|
||||
"https://deno.land/x/zod@v3.22.4/helpers/partialUtil.ts": "998c2fe79795257d4d1cf10361e74492f3b7d852f61057c7c08ac0a46488b7e7",
|
||||
"https://deno.land/x/zod@v3.22.4/helpers/typeAliases.ts": "0fda31a063c6736fc3cf9090dd94865c811dfff4f3cb8707b932bf937c6f2c3e",
|
||||
"https://deno.land/x/zod@v3.22.4/helpers/util.ts": "8baf19b19b2fca8424380367b90364b32503b6b71780269a6e3e67700bb02774",
|
||||
"https://deno.land/x/zod@v3.22.4/index.ts": "d27aabd973613985574bc31f39e45cb5d856aa122ef094a9f38a463b8ef1a268",
|
||||
"https://deno.land/x/zod@v3.22.4/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c",
|
||||
"https://deno.land/x/zod@v3.22.4/mod.ts": "64e55237cb4410e17d968cd08975566059f27638ebb0b86048031b987ba251c4",
|
||||
"https://deno.land/x/zod@v3.22.4/types.ts": "724185522fafe43ee56a52333958764c8c8cd6ad4effa27b42651df873fc151e"
|
||||
"https://deno.land/std@0.208.0/streams/zip_readable_streams.ts": "721c5bce8862c8225e60995b2d61c7b1b1d5b5178b60d303a01f453d5c26bb62"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#!/bin/env -S deno run -A --unstable
|
||||
|
||||
import { daemon_send, new_cmd_disable, new_cmd_enable, new_cmd_status, new_cmd_stop } from "./src/lib.ts";
|
||||
import { ContainerConfig } from "./src/lib/config.ts";
|
||||
import { load_all_container_configs, new_container_config, save_container_config } from "./src/lib/config.ts";
|
||||
import { load_base, new_container_context } from "./src/lib/create.ts";
|
||||
import { container_paths, socket_path } from "./src/lib/paths.ts";
|
||||
import { async_collect } from "./src/lib/utils.ts";
|
||||
import { log_from, run } from "./src/lib/utils.ts";
|
||||
|
||||
const log = log_from("control");
|
||||
|
@ -79,16 +78,16 @@ Commands:
|
|||
export async function create(name: string, base_name: string) {
|
||||
log("loading base", base_name);
|
||||
const base = await load_base(base_name);
|
||||
const known_containers = await async_collect(ContainerConfig.load_all());
|
||||
const known_containers = await load_all_container_configs();
|
||||
|
||||
const paths = container_paths(name);
|
||||
await Deno.mkdir(paths.base);
|
||||
const configuration = ContainerConfig.new_default(name);
|
||||
const configuration = new_container_config(name);
|
||||
|
||||
log("creating the container", name, "at", paths.base);
|
||||
const context = new_container_context(paths.root, configuration, known_containers);
|
||||
await Deno.mkdir(paths.root);
|
||||
await run("sudo", "chown", "root:root", paths.root);
|
||||
await base.build(context);
|
||||
await configuration.save();
|
||||
await save_container_config(configuration);
|
||||
}
|
||||
|
|
|
@ -1,19 +1,29 @@
|
|||
#!/bin/env -S deno run -A --unstable
|
||||
|
||||
import { daemon_listen, Runner } from "./src/lib.ts";
|
||||
import { ContainerConfig } from "./src/lib/config.ts";
|
||||
import { NginxController } from "./src/lib/nginx.ts";
|
||||
import { daemon_listen, Runner, start_runner } from "./src/lib.ts";
|
||||
import { load_container_config } from "./src/lib/config.ts";
|
||||
import { socket_path, state_path } from "./src/lib/paths.ts";
|
||||
import { log_from, sleep } from "./src/lib/utils.ts";
|
||||
|
||||
const log = log_from("daemon");
|
||||
|
||||
if (import.meta.main) await main();
|
||||
async function main() {
|
||||
const state = await State.load();
|
||||
const state = await create_state();
|
||||
const server = await daemon_listen(socket_path());
|
||||
log("listening to", socket_path());
|
||||
|
||||
const finish = termination_function(state, server.server);
|
||||
async function finish() {
|
||||
log("stopping");
|
||||
server.server.close();
|
||||
for (const runner of state.enabled.values()) {
|
||||
try {
|
||||
await runner.stop();
|
||||
} catch (_) { /* on s'en fou */ }
|
||||
}
|
||||
await Deno.remove(socket_path());
|
||||
Deno.exit(0);
|
||||
}
|
||||
Deno.addSignalListener("SIGINT", finish);
|
||||
|
||||
for await (const { cmd, respond } of server) {
|
||||
|
@ -77,71 +87,41 @@ async function main() {
|
|||
}
|
||||
}
|
||||
|
||||
class State {
|
||||
enabled;
|
||||
nginx;
|
||||
|
||||
constructor() {
|
||||
this.enabled = new Map<string, Runner>();
|
||||
this.nginx = new NginxController("barnulf.net", "/etc/nginx/sites-enabled");
|
||||
}
|
||||
|
||||
static async load() {
|
||||
const result = new State();
|
||||
try {
|
||||
log("trying to recover state from", state_path());
|
||||
const loaded = JSON.parse(await Deno.readTextFile(state_path()));
|
||||
for (const name of loaded.enabled ?? []) {
|
||||
await result.enable(name);
|
||||
}
|
||||
log("successfully loaded from", state_path());
|
||||
} catch (error) {
|
||||
log("experienced failure", error);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async enable(name: string) {
|
||||
if (this.enabled.has(name)) throw new Error("Container already enabled");
|
||||
log("loading container", name);
|
||||
const config = await ContainerConfig.load(name); // TODO
|
||||
if (config === null) throw new Error("can't read config");
|
||||
log("starting container", name);
|
||||
const runner = new Runner(config, this.nginx);
|
||||
runner.start();
|
||||
this.enabled.set(name, runner);
|
||||
log("container", name, "started");
|
||||
}
|
||||
|
||||
async disable(name: string) {
|
||||
const container = this.enabled.get(name);
|
||||
if (container === undefined) throw new Error("Container not found");
|
||||
await container.stop();
|
||||
this.enabled.delete(name);
|
||||
}
|
||||
|
||||
list() {
|
||||
return Array.from(this.enabled.keys());
|
||||
}
|
||||
|
||||
async save() {
|
||||
const content = JSON.stringify({ enabled: this.list() });
|
||||
await Deno.writeTextFile(state_path(), content);
|
||||
}
|
||||
}
|
||||
|
||||
function termination_function(state: State, server: Deno.Listener<Deno.Conn>) {
|
||||
return async function finish() {
|
||||
log("stopping");
|
||||
server.close();
|
||||
for (const runner of state.enabled.values()) {
|
||||
try {
|
||||
await runner.stop();
|
||||
} catch (_) { /* on s'en fou */ }
|
||||
}
|
||||
await Deno.remove(socket_path());
|
||||
Deno.exit(0);
|
||||
async function create_state() {
|
||||
const self = {
|
||||
enabled: new Map<string, Runner>(),
|
||||
async enable(name: string) {
|
||||
if (self.enabled.has(name)) throw new Error("Container already enabled");
|
||||
log("loading container", name);
|
||||
const config = await load_container_config(name); // TODO
|
||||
if (config === null) throw new Error("can't read config");
|
||||
log("starting container", name);
|
||||
self.enabled.set(name, await start_runner(config));
|
||||
log("container", name, "started");
|
||||
},
|
||||
async disable(name: string) {
|
||||
const container = self.enabled.get(name);
|
||||
if (container === undefined) throw new Error("Container not found");
|
||||
await container.stop();
|
||||
self.enabled.delete(name);
|
||||
},
|
||||
list() {
|
||||
return Array.from(self.enabled.keys());
|
||||
},
|
||||
async save() {
|
||||
const content = JSON.stringify({ enabled: self.list() });
|
||||
await Deno.writeTextFile(state_path(), content);
|
||||
},
|
||||
};
|
||||
try {
|
||||
log("trying to recover state from", state_path());
|
||||
const loaded = JSON.parse(await Deno.readTextFile(state_path()));
|
||||
for (const name of loaded.enabled ?? []) {
|
||||
await self.enable(name);
|
||||
}
|
||||
log("successfully loaded from", state_path());
|
||||
} catch (error) {
|
||||
log("experienced failure", error);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
if (import.meta.main) await main();
|
||||
|
|
|
@ -5,8 +5,6 @@ import { lines, log_from, loop_process, run } from "./lib/utils.ts";
|
|||
import { ContainerConfig } from "./lib/config.ts";
|
||||
import { container_paths } from "./lib/paths.ts";
|
||||
import { container_command } from "./lib/nspawn.ts";
|
||||
import { LoopProcess } from "./lib/utils.ts";
|
||||
import { NginxController } from "./lib/nginx.ts";
|
||||
|
||||
const log = log_from("lib");
|
||||
|
||||
|
@ -68,57 +66,28 @@ export async function daemon_send(sock_path: string, command: Cmd) {
|
|||
return await toText(request.readable);
|
||||
}
|
||||
|
||||
export class Runner {
|
||||
name;
|
||||
config;
|
||||
nginx;
|
||||
loop;
|
||||
|
||||
constructor(config: ContainerConfig, nginx: NginxController) {
|
||||
this.name = config.name;
|
||||
this.config = config;
|
||||
this.nginx = nginx;
|
||||
this.loop = null as LoopProcess | null;
|
||||
}
|
||||
|
||||
start() {
|
||||
this.update_proxies();
|
||||
this.start_process();
|
||||
}
|
||||
|
||||
private start_process() {
|
||||
const paths = container_paths(this.name);
|
||||
const command = container_command(this.name, paths.root, {
|
||||
boot: true,
|
||||
veth: true,
|
||||
redirections: this.config.redirections,
|
||||
cmd_opts: {
|
||||
stdin: "null",
|
||||
stdout: "null",
|
||||
},
|
||||
syscall_filter: ["add_key", "keyctl", "bpf"],
|
||||
});
|
||||
this.loop = loop_process(command, {
|
||||
on_start: () => log("container", this.name, "started"),
|
||||
on_stop: () => log("container", this.name, "stopped"),
|
||||
});
|
||||
}
|
||||
|
||||
async stop() {
|
||||
await this.loop?.kill();
|
||||
}
|
||||
|
||||
async update_proxies() {
|
||||
const paths = container_paths(this.name);
|
||||
await Deno.mkdir(paths.sites, { recursive: true });
|
||||
const sites = new Set<string>();
|
||||
for (const redir of this.config.redirections) {
|
||||
if (redir.kind !== "http") continue;
|
||||
await this.nginx.add_proxy(redir.domain, redir.port, paths.sites);
|
||||
sites.add(redir.domain);
|
||||
}
|
||||
for await (const domains of this.nginx.read_all_in_dir(paths.sites)) {
|
||||
if (!sites.has(domains)) this.nginx.remove_proxy(domains, paths.sites);
|
||||
}
|
||||
}
|
||||
export type Runner = Awaited<ReturnType<typeof start_runner>>;
|
||||
export function start_runner(config: ContainerConfig) {
|
||||
const { name } = config;
|
||||
const paths = container_paths(name);
|
||||
const command = container_command(name, paths.root, {
|
||||
boot: true,
|
||||
veth: true,
|
||||
ports: config.redirects,
|
||||
cmd_opts: {
|
||||
stdin: "null",
|
||||
stdout: "null",
|
||||
},
|
||||
syscall_filter: ["add_key", "keyctl", "bpf"],
|
||||
});
|
||||
const container_loop = loop_process(command, {
|
||||
on_start: () => log("container", name, "started"),
|
||||
on_stop: () => log("container", name, "stopped"),
|
||||
});
|
||||
return {
|
||||
name,
|
||||
config,
|
||||
container_loop,
|
||||
stop: () => container_loop.kill(),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,106 +1,59 @@
|
|||
import { container_paths, containers_path, state_config_path } from "./paths.ts";
|
||||
import { log_from } from "./utils.ts";
|
||||
import { exists, log_from } from "./utils.ts";
|
||||
import { z } from "https://deno.land/x/zod@v3.22.4/mod.ts";
|
||||
|
||||
const log = log_from("config");
|
||||
|
||||
export type StateConfig = ReturnType<typeof new_config>;
|
||||
export function new_config(app_key: string, app_secret: string, consumer_key: string) {
|
||||
return { app_key, app_secret, consumer_key };
|
||||
export function new_container_config(name: string): ContainerConfig {
|
||||
return {
|
||||
name,
|
||||
version: 0,
|
||||
redirects: [] as [number, number][],
|
||||
};
|
||||
}
|
||||
|
||||
export async function load_state_config() {
|
||||
try {
|
||||
const content = await Deno.readTextFile(state_config_path());
|
||||
return JSON.parse(content) as StateConfig;
|
||||
} catch (_) {
|
||||
const result = new_config("APP_KEY", "APP_SECRET", "CONSUMER_KEY");
|
||||
const content = JSON.stringify(result);
|
||||
await Deno.writeTextFile(state_config_path(), content);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
const CONTAINER_CONFIG_VERSION = 1;
|
||||
|
||||
export class ContainerConfig {
|
||||
name;
|
||||
redirections;
|
||||
|
||||
constructor(name: string, redirections: ContainerConfigRedirection[]) {
|
||||
this.name = name;
|
||||
this.redirections = redirections;
|
||||
}
|
||||
|
||||
public static new_default(name: string) {
|
||||
return new ContainerConfig(name, []);
|
||||
}
|
||||
|
||||
public static async load(name: string) {
|
||||
const path = container_paths(name).configuration;
|
||||
const content = await Deno.readTextFile(path);
|
||||
return ContainerConfig.deserialize(content);
|
||||
}
|
||||
|
||||
public async save() {
|
||||
const path = container_paths(this.name).configuration;
|
||||
await Deno.writeTextFile(path, this.serialize());
|
||||
}
|
||||
|
||||
public static async *load_all() {
|
||||
for await (const { isDirectory, name } of Deno.readDir(containers_path())) {
|
||||
if (!isDirectory) continue;
|
||||
yield await ContainerConfig.load(name);
|
||||
}
|
||||
}
|
||||
|
||||
public static deserialize(raw: string) {
|
||||
const unknown = JSON.parse(raw);
|
||||
const parsed = parse(unknown);
|
||||
return new ContainerConfig(parsed.name, parsed.redirections);
|
||||
}
|
||||
|
||||
public serialize() {
|
||||
const raw: SerializedContainerConfig = {
|
||||
version: CONTAINER_CONFIG_VERSION,
|
||||
name: this.name,
|
||||
redirections: this.redirections,
|
||||
};
|
||||
return JSON.stringify(raw, null, 4);
|
||||
}
|
||||
|
||||
public *used_host_ports() {
|
||||
for (const redir of this.redirections) {
|
||||
if (redir.kind === "http") yield redir.port;
|
||||
if (redir.kind === "port") yield redir.from;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parse(input: unknown) {
|
||||
const redir_port = z.object({
|
||||
kind: z.literal("port"),
|
||||
from: z.number(),
|
||||
to: z.number(),
|
||||
});
|
||||
|
||||
const redir_http = z.object({
|
||||
kind: z.literal("http"),
|
||||
tls: z.boolean(),
|
||||
port: z.number(),
|
||||
domain: z.string(),
|
||||
});
|
||||
|
||||
// TODO : redir DNS SRV
|
||||
|
||||
const redirection = redir_http.or(redir_port);
|
||||
|
||||
export type ContainerConfig = ReturnType<typeof parse_container_config>;
|
||||
export function parse_container_config(json: string) {
|
||||
return z.object({
|
||||
name: z.string(),
|
||||
version: z.number(),
|
||||
redirections: z.array(redirection),
|
||||
}).parse(input);
|
||||
redirects: z.array(
|
||||
z
|
||||
.tuple([
|
||||
z.number(),
|
||||
z.number(),
|
||||
])
|
||||
.or(z.tuple([
|
||||
z.number(),
|
||||
z.number(),
|
||||
z.literal("tcp").or(z.literal("udp")),
|
||||
])),
|
||||
),
|
||||
}).parse(JSON.parse(json));
|
||||
}
|
||||
|
||||
type SerializedContainerConfig = ReturnType<typeof parse>;
|
||||
export type ContainerConfigRedirection = SerializedContainerConfig["redirections"][0];
|
||||
export async function load_container_config(name: string) {
|
||||
const config_path = container_paths(name).configuration;
|
||||
log("loading config for", name);
|
||||
if (!exists(config_path)) return null;
|
||||
const content = await Deno.readTextFile(config_path);
|
||||
const read = parse_container_config(content);
|
||||
const default_ = new_container_config(name);
|
||||
if (read.version < default_.version) throw new Error("read conf version is outdated");
|
||||
return { ...default_, ...read } as ContainerConfig;
|
||||
}
|
||||
|
||||
export async function save_container_config(config: ContainerConfig) {
|
||||
log("saving config of", config.name);
|
||||
const config_path = container_paths(config.name).configuration;
|
||||
const serialized = JSON.stringify(config, null, 4);
|
||||
await Deno.writeTextFile(config_path, serialized);
|
||||
}
|
||||
|
||||
export async function load_all_container_configs() {
|
||||
const names = Array.from(Deno.readDirSync(containers_path()))
|
||||
.filter((e) => e.isDirectory)
|
||||
.map((e) => e.name);
|
||||
const results = await Promise.all(names.map((name) => load_container_config(name)));
|
||||
return results.filter((item) => item != null) as ContainerConfig[];
|
||||
}
|
||||
|
|
|
@ -37,11 +37,11 @@ export function new_container_context(root_dir: string, config: ContainerConfig,
|
|||
},
|
||||
redirect: (from: number, to: number) => {
|
||||
log("redirects", from, "to", to);
|
||||
config.redirections.push({ kind: "port", from, to });
|
||||
config.redirects.push([from, to]);
|
||||
},
|
||||
available_port: (target: number) => {
|
||||
const used_by_known_containers = known_containers.map((c) => [...c.used_host_ports()]).flat();
|
||||
const used_by_self = config.used_host_ports();
|
||||
const used_by_known_containers = known_containers.map((c) => c.redirects[0]).flat();
|
||||
const used_by_self = config.redirects.map((r) => r[0]);
|
||||
const used = [...used_by_known_containers, ...used_by_self];
|
||||
let result = target;
|
||||
while (used.includes(result)) result += 1;
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
import { run } from "./utils.ts";
|
||||
import * as path from "https://deno.land/std@0.214.0/path/mod.ts";
|
||||
|
||||
export class NginxController {
|
||||
private proxy_target_domain;
|
||||
private enabled_conf_dir;
|
||||
|
||||
constructor(proxy_target_domain: string, enabled_conf_dir: string) {
|
||||
this.proxy_target_domain = proxy_target_domain;
|
||||
this.enabled_conf_dir = enabled_conf_dir;
|
||||
}
|
||||
|
||||
public async add_proxy(domain: string, port: number, conf_dir: string) {
|
||||
const conf_file_content = `
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name ${domain};
|
||||
location / {
|
||||
proxy_pass http://${this.proxy_target_domain}:${port};
|
||||
}
|
||||
}
|
||||
`;
|
||||
const conf_file_path = path.join(conf_dir, domain + ".conf");
|
||||
const enabled_conf_file_path = path.join(this.enabled_conf_dir, domain + ".conf");
|
||||
await Deno.writeTextFile(conf_file_path, conf_file_content);
|
||||
await run("ln", "-s", await Deno.realPath(conf_file_path), enabled_conf_file_path);
|
||||
await this.reload();
|
||||
return conf_file_path;
|
||||
}
|
||||
|
||||
public async remove_proxy(domain: string, conf_dir: string) {
|
||||
const conf_file_path = path.join(conf_dir, domain + ".conf");
|
||||
const enabled_conf_file_path = path.join(this.enabled_conf_dir, domain + ".conf");
|
||||
await Deno.remove(enabled_conf_file_path, { recursive: true });
|
||||
await Deno.remove(conf_file_path, { recursive: true });
|
||||
await this.reload();
|
||||
}
|
||||
|
||||
public async *read_all_in_dir(conf_dir: string) {
|
||||
for await (const { name } of Deno.readDir(conf_dir)) {
|
||||
const [domain, rest] = name.split(".conf");
|
||||
if (rest !== "") continue;
|
||||
yield domain;
|
||||
}
|
||||
}
|
||||
|
||||
private async reload() {
|
||||
await run("systemctl", "restart", "nginx");
|
||||
}
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
// wrapper
|
||||
|
||||
import { log_from, sleep } from "./utils.ts";
|
||||
import { ContainerConfigRedirection } from "./config.ts";
|
||||
|
||||
const log = log_from("nspawn");
|
||||
|
||||
export function container_command(name: string, directory: string, opts?: {
|
||||
veth?: boolean;
|
||||
boot?: boolean;
|
||||
redirections?: ContainerConfigRedirection[];
|
||||
ports?: ([number, number] | [number, number, "tcp" | "udp"])[];
|
||||
cmd_opts?: Deno.CommandOptions;
|
||||
syscall_filter?: string[];
|
||||
}) {
|
||||
|
@ -18,12 +17,8 @@ export function container_command(name: string, directory: string, opts?: {
|
|||
];
|
||||
if (opts?.veth ?? false) args.push("--network-veth");
|
||||
if (opts?.boot ?? false) args.push("--boot");
|
||||
for (const redir of opts?.redirections ?? []) {
|
||||
if (redir.kind === "http") args.push(`--port=${redir.port}`);
|
||||
if (redir.kind === "port") {
|
||||
args.push(`--port=tcp:${redir.from}:${redir.to}`);
|
||||
args.push(`--port=udp:${redir.from}:${redir.to}`);
|
||||
}
|
||||
for (const [from, to, proto] of opts?.ports ?? []) {
|
||||
args.push(proto === undefined ? `--port=${from}:${to}` : `--port=${proto}:${from}:${to}`);
|
||||
}
|
||||
for (const call of opts?.syscall_filter ?? []) args.push(`--system-call-filter=${call}`);
|
||||
const command = new Deno.Command("systemd-nspawn", { ...opts?.cmd_opts, args });
|
||||
|
|
|
@ -18,8 +18,7 @@ export function container_paths(name: string) {
|
|||
const base = containers_path() + "/" + name;
|
||||
const configuration = base + "/config.json";
|
||||
const root = base + "/root";
|
||||
const sites = base + "/sites";
|
||||
return { base, configuration, root, sites };
|
||||
return { base, configuration, root };
|
||||
}
|
||||
|
||||
export function state_path() {
|
||||
|
@ -35,7 +34,3 @@ export function base_paths(name: string) {
|
|||
const module = base + "/module.ts";
|
||||
return { base, module };
|
||||
}
|
||||
|
||||
export function state_config_path() {
|
||||
return instance_root_path() + "/local/config.json";
|
||||
}
|
||||
|
|
|
@ -53,22 +53,17 @@ export function loop_process(
|
|||
on_start: opts?.on_start ?? async_noop,
|
||||
on_stop: opts?.on_stop ?? async_noop,
|
||||
};
|
||||
const control = {
|
||||
do_continue: true,
|
||||
child_process: null as null | Deno.ChildProcess,
|
||||
};
|
||||
const kill_sig = channel<"kill">();
|
||||
kill_sig.receive().then(() => {
|
||||
control.do_continue = false;
|
||||
try {
|
||||
control.child_process?.kill();
|
||||
} catch (_) { /* isok */ }
|
||||
});
|
||||
async function launch() {
|
||||
while (control.do_continue) {
|
||||
while (true) {
|
||||
await events.on_start();
|
||||
control.child_process = command.spawn();
|
||||
await control.child_process.output();
|
||||
const child_process = command.spawn();
|
||||
const result = await Promise.any([kill_sig.receive(), child_process.output()]);
|
||||
if (result === "kill") {
|
||||
await events.on_stop();
|
||||
child_process.kill();
|
||||
break;
|
||||
}
|
||||
await events.on_stop();
|
||||
await sleep(opts?.delay ?? 500);
|
||||
}
|
||||
|
@ -98,9 +93,3 @@ export function log_from(...prefixes: string[]) {
|
|||
console.log(prefix, ...args);
|
||||
};
|
||||
}
|
||||
|
||||
export async function async_collect<T>(gen: AsyncIterable<T>) {
|
||||
const result = [] as T[];
|
||||
for await (const item of gen) result.push(item);
|
||||
return result;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue