Implement packwiz serve

This commit is contained in:
Moritz Ruth 2022-08-16 16:59:44 +02:00
parent 68b849df0c
commit 6345c7e151
4 changed files with 155 additions and 8 deletions

View file

@ -23,6 +23,7 @@
},
"dependencies": {
"@root/walk": "^1.1.0",
"address": "^1.2.0",
"commander": "^9.4.0",
"dedent": "^0.7.0",
"env-paths": "^3.0.0",
@ -41,6 +42,7 @@
"p-limit": "^4.0.0",
"s-ago": "^2.2.0",
"semver": "^7.3.7",
"serve-handler": "^6.1.3",
"wrap-ansi": "^8.0.1",
"yazl": "^2.5.1",
"zod": "^3.18.0"
@ -51,6 +53,7 @@
"@types/lodash-es": "^4.17.6",
"@types/node": "^18.7.3",
"@types/semver": "^7.3.12",
"@types/serve-handler": "^6.1.1",
"@types/wrap-ansi": "^8.0.1",
"@types/yazl": "^2.4.2",
"tsx": "^3.8.2",

96
pnpm-lock.yaml generated
View file

@ -7,8 +7,10 @@ specifiers:
'@types/lodash-es': ^4.17.6
'@types/node': ^18.7.3
'@types/semver': ^7.3.12
'@types/serve-handler': ^6.1.1
'@types/wrap-ansi': ^8.0.1
'@types/yazl': ^2.4.2
address: ^1.2.0
commander: ^9.4.0
dedent: ^0.7.0
env-paths: ^3.0.0
@ -27,6 +29,7 @@ specifiers:
p-limit: ^4.0.0
s-ago: ^2.2.0
semver: ^7.3.7
serve-handler: ^6.1.3
tsx: ^3.8.2
type-fest: ^2.18.0
typescript: ^4.7.4
@ -36,6 +39,7 @@ specifiers:
dependencies:
'@root/walk': 1.1.0
address: 1.2.0
commander: 9.4.0
dedent: 0.7.0
env-paths: 3.0.0
@ -54,6 +58,7 @@ dependencies:
p-limit: 4.0.0
s-ago: 2.2.0
semver: 7.3.7
serve-handler: 6.1.3
wrap-ansi: 8.0.1
yazl: 2.5.1
zod: 3.18.0
@ -64,6 +69,7 @@ devDependencies:
'@types/lodash-es': 4.17.6
'@types/node': 18.7.3
'@types/semver': 7.3.12
'@types/serve-handler': 6.1.1
'@types/wrap-ansi': 8.0.1
'@types/yazl': 2.4.2
tsx: 3.8.2
@ -174,6 +180,12 @@ packages:
resolution: {integrity: sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==}
dev: true
/@types/serve-handler/6.1.1:
resolution: {integrity: sha512-bIwSmD+OV8w0t2e7EWsuQYlGoS1o5aEdVktgkXaa43Zm0qVWi21xaSRb3DQA1UXD+DJ5bRq1Rgu14ZczB+CjIQ==}
dependencies:
'@types/node': 18.7.3
dev: true
/@types/wrap-ansi/8.0.1:
resolution: {integrity: sha512-cjwgM6WWy9YakrQ36Pq0vg5XoNblVEaNq+/pHngKl4GyyDIxTeskPoG+tp4LsRk0lHrA4LaLJqlvYridi7mzlw==}
dev: true
@ -184,6 +196,11 @@ packages:
'@types/node': 18.7.3
dev: true
/address/1.2.0:
resolution: {integrity: sha512-tNEZYz5G/zYunxFm7sfhAxkXEuLj3K6BKwv6ZURlsF6yiUQ65z0Q2wZW9L5cPUl9ocofGvXOdFYbFHp0+6MOig==}
engines: {node: '>= 10.0.0'}
dev: false
/ansi-regex/6.0.1:
resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
engines: {node: '>=12'}
@ -199,6 +216,10 @@ packages:
engines: {node: '>=0.10.0'}
dev: false
/balanced-match/1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: false
/base64-js/1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: false
@ -211,6 +232,13 @@ packages:
readable-stream: 3.6.0
dev: false
/brace-expansion/1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
dev: false
/buffer-crc32/0.2.13:
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
dev: false
@ -226,6 +254,11 @@ packages:
ieee754: 1.2.1
dev: false
/bytes/3.0.0:
resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==}
engines: {node: '>= 0.8'}
dev: false
/cacheable-lookup/6.1.0:
resolution: {integrity: sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==}
engines: {node: '>=10.6.0'}
@ -285,6 +318,15 @@ packages:
json-buffer: 3.0.1
dev: false
/concat-map/0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: false
/content-disposition/0.5.2:
resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==}
engines: {node: '>= 0.6'}
dev: false
/currently-unhandled/0.4.1:
resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==}
engines: {node: '>=0.10.0'}
@ -559,6 +601,12 @@ packages:
engines: {node: '>=12'}
dev: false
/fast-url-parser/1.1.3:
resolution: {integrity: sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==}
dependencies:
punycode: 1.4.1
dev: false
/figures/5.0.0:
resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==}
engines: {node: '>=14'}
@ -771,6 +819,18 @@ packages:
yallist: 4.0.0
dev: false
/mime-db/1.33.0:
resolution: {integrity: sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==}
engines: {node: '>= 0.6'}
dev: false
/mime-types/2.1.18:
resolution: {integrity: sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==}
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.33.0
dev: false
/mimic-fn/2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
@ -786,6 +846,12 @@ packages:
engines: {node: '>=10'}
dev: false
/minimatch/3.0.4:
resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==}
dependencies:
brace-expansion: 1.1.11
dev: false
/ms/2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: false
@ -865,6 +931,14 @@ packages:
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dev: false
/path-is-inside/1.0.2:
resolution: {integrity: sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==}
dev: false
/path-to-regexp/2.2.1:
resolution: {integrity: sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==}
dev: false
/pump/3.0.0:
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
dependencies:
@ -872,11 +946,20 @@ packages:
once: 1.4.0
dev: false
/punycode/1.4.1:
resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==}
dev: false
/quick-lru/5.1.1:
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
engines: {node: '>=10'}
dev: false
/range-parser/1.2.0:
resolution: {integrity: sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==}
engines: {node: '>= 0.6'}
dev: false
/readable-stream/3.6.0:
resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
engines: {node: '>= 6'}
@ -920,6 +1003,19 @@ packages:
lru-cache: 6.0.0
dev: false
/serve-handler/6.1.3:
resolution: {integrity: sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==}
dependencies:
bytes: 3.0.0
content-disposition: 0.5.2
fast-url-parser: 1.1.3
mime-types: 2.1.18
minimatch: 3.0.4
path-is-inside: 1.0.2
path-to-regexp: 2.2.1
range-parser: 1.2.0
dev: false
/signal-exit/3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
dev: false

View file

@ -3,7 +3,7 @@ import { usePack } from "../pack.js"
import fs from "fs-extra"
import dedent from "dedent"
import kleur from "kleur"
import { getSha512HexHash } from "../utils.js"
import { getLANAddress, getSha512HexHash, httpServeDirectory, optionParsePositiveInteger } from "../utils.js"
import { output } from "../output.js"
import { Visitor, walk } from "@root/walk"
import { Path } from "../path.js"
@ -25,9 +25,28 @@ packwizCommand.command("import")
packwizCommand.command("serve")
.description("Start an HTTP server in the packwiz directory.")
.action(async () => {
output.failAndExit("Not implemented.")
// TODO: serve
.option("-p, --port <port>", "The port of the HTTP server.", optionParsePositiveInteger, 8000)
.option("-e, --expose", "Expose the HTTP server on all interfaces.")
.action(async options => {
const pack = await usePack()
const directoryPath = pack.paths.generated.resolve("packwiz")
if (!(await fs.pathExists(directoryPath.toString())))
output.failAndExit(`The ${kleur.yellow("packwiz")} directory does not exist. Generate it by running ${kleur.yellow("horizr packwiz export")}.`)
const lanAddress = await getLANAddress()
httpServeDirectory(directoryPath, options.port, options.expose, () => {
const localAddress = `http://localhost:${options.port}/pack.toml`
if (options.expose) {
output.println(dedent`
${kleur.green("Serving at")}
Local: ${kleur.yellow(localAddress)}
Network: ${kleur.yellow(`http://${lanAddress}:${options.port}/pack.toml`)}
`)
}
else output.println(`${kleur.green("Serving at")} ${kleur.yellow(localAddress)}`)
})
})
packwizCommand.command("dev")
@ -92,8 +111,6 @@ packwizCommand.command("export")
if (dirent.isFile()) {
const outputPath = outputDirectoryPath.resolve(relativePath)
await fs.mkdirp(outputPath.getParent().toString())
console.log(path)
console.log(outputPath.toString())
await fs.copy(path, outputPath.toString())
indexedFiles.push({

View file

@ -5,6 +5,37 @@ import { ZipFile } from "yazl"
import { walk } from "@root/walk"
import fs from "fs-extra"
import { pEvent } from "p-event"
import serveHandler from "serve-handler"
import * as http from "http"
import addressWithCallback from "address"
import { promisify } from "util"
const address = promisify(addressWithCallback)
export const getLANAddress = () => address().then(r => r.ip)
export function httpServeDirectory(path: Path, port: number, expose: boolean, onListen: () => void) {
const server = http.createServer((request, response) => {
return serveHandler(request, response, {
directoryListing: false,
public: path.toString(),
cleanUrls: false,
headers: [
{
source: "**/*.toml",
headers: [{
key: "Content-Type",
value: "application/toml"
}]
}
]
})
})
server.listen(port, expose ? "0.0.0.0" : "127.0.0.1", () => {
onListen()
})
}
export async function zipDirectory(directoryPath: Path, outputFilePath: Path) {
const zipFile = new ZipFile()