2025-02-19 20:04:49 +00:00

167 lines
4.0 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Server } from "linebridge"
import LiveDirectory from "live-directory"
import * as Setup from "./lib/setupDist"
import crypto from "node:crypto"
import path from "node:path"
import fs from "node:fs"
class WebWrapper extends Server {
static disableBaseEndpoints = true
static listenPort = process.env.HTTP_LISTEN_PORT || 5000
static publicPath = path.resolve(process.cwd(), "public")
static appDistPath = path.resolve(process.cwd(), "public/dist")
static cachePath = path.resolve(process.cwd(), ".cache")
static appManifestPath = path.resolve(this.publicPath, "manifest.json")
static distCompressedFile = "dist.zip"
static repoName = "ragestudio/comty"
routes = {
"/*": {
method: "get",
fn: async (req, res) => {
let file = global.staticLiveDirectory.get(req.path)
if (file === undefined) {
file = global.staticLiveDirectory.get("index.html")
}
if (file === undefined) {
return res.status(404).json({ error: "Not found" })
}
const fileParts = file.path.split(".")
const extension = fileParts[fileParts.length - 1]
let content = file.content
if (!content) {
content = file.stream()
}
if (!content) {
return res
.status(500)
.json({ error: "Cannot read this file" })
}
if (content instanceof Buffer) {
return res.type(extension).send(content)
} else {
return res.type(extension).stream(content)
}
},
},
}
async updateDistApp() {
if (fs.existsSync(WebWrapper.appDistPath)) {
await fs.promises.rm(WebWrapper.appDistPath, { recursive: true })
}
await Setup.setupLatestRelease({
repository: WebWrapper.repoName,
distCompressedFile: WebWrapper.distCompressedFile,
destinationPath: WebWrapper.publicPath,
cachePath: WebWrapper.cachePath,
})
}
async handleUpdateWebhook(req, res) {
const bodyBuff = await req.buffer()
const requestSignature = Buffer.from(
req.headers["x-hub-signature-256"] || "",
"utf8",
)
const hmac = crypto.createHmac(
"sha256",
process.env.WRAPPER_AUTO_UPDATE_KEY,
)
const digest = Buffer.from(
"sha256" + "=" + hmac.update(bodyBuff).digest("hex"),
"utf8",
)
// if signatures not match, return error
if (
requestSignature.length !== digest.length ||
!crypto.timingSafeEqual(digest, requestSignature)
) {
return res.status(401).json({ error: "Invalid signature" })
}
if (req.body.action !== "published") {
return res.status(400).json({ error: "Invalid action" })
}
// return ok and schedule update for the 30 seconds
console.log("[WEBHOOK] Update app dist triggered >", {
sig: req.headers["x-hub-signature-256"],
})
res.status(200).json({ ok: true })
setTimeout(async () => {
await this.updateDistApp()
await this.listenLiveDirectory()
}, 30000)
}
async listenLiveDirectory() {
global.staticLiveDirectory = new LiveDirectory(WebWrapper.appDistPath, {
static: false,
})
}
async onInitialize() {
if (process.env.WRAPPER_AUTO_UPDATE_KEY) {
console.log("Auto update key is set, enabling webhook update")
this.register.http({
method: "POST",
route: "/webhooks/update",
fn: this.handleUpdateWebhook.bind(this),
})
}
if (!fs.existsSync(WebWrapper.publicPath)) {
console.log("Creating public path...")
fs.mkdirSync(WebWrapper.publicPath)
}
if (!fs.existsSync(WebWrapper.appManifestPath)) {
console.log(` Missing app manifest/dist, installing...`)
await this.updateDistApp()
}
let manifest = await fs.promises.readFile(
WebWrapper.appManifestPath,
"utf8",
)
manifest = JSON.parse(manifest)
const latestRelease = await Setup.getLatestReleaseFromGithub(
WebWrapper.repoName,
).catch(() => null)
if (latestRelease) {
if (latestRelease.tag_name !== manifest.version) {
console.log(
`🔰 New version available: ${latestRelease.tag_name}, updating...`,
)
await this.updateDistApp()
} else {
console.log(`✅ App dist is up to date!`)
}
}
await this.listenLiveDirectory()
}
}
Boot(WebWrapper)