mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 18:44:16 +00:00
rewrite wrapper
This commit is contained in:
parent
028f14f12b
commit
54c7c3c59d
2
packages/wrapper/.gitignore
vendored
Normal file
2
packages/wrapper/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
public
|
||||||
|
.cache
|
12
packages/wrapper/package.json
Executable file
12
packages/wrapper/package.json
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "@comty/wrapper",
|
||||||
|
"version": "1.25.0-a",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"start": "linebridge-boot ./src/index.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"linebridge": "^0.22.3",
|
||||||
|
"live-directory": "^3.0.3"
|
||||||
|
}
|
||||||
|
}
|
103
packages/wrapper/src/bindex.js
Normal file
103
packages/wrapper/src/bindex.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import path from "node:path"
|
||||||
|
import fs from "node:fs"
|
||||||
|
import HyperExpress from "hyper-express"
|
||||||
|
import LiveDirectory from "live-directory"
|
||||||
|
|
||||||
|
const { WebSocket: WSClient } = require("ws")
|
||||||
|
const http = require("http")
|
||||||
|
|
||||||
|
// CONFIGURATION CONSTANTS
|
||||||
|
const publicPath = path.resolve(process.cwd(), "public")
|
||||||
|
const TARGET_HTTP = "http://localhost:9000"
|
||||||
|
const TARGET_WS = "ws://localhost:8080"
|
||||||
|
const LISTENT_PORT = 9999
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
if (!fs.existsSync(publicPath)) {
|
||||||
|
console.log("Public path does not exist, creating...")
|
||||||
|
fs.mkdirSync(publicPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = new HyperExpress.Server()
|
||||||
|
const liveDirectory = new LiveDirectory(publicPath)
|
||||||
|
|
||||||
|
app.any("/*", async (req, res) => {
|
||||||
|
if (req.url.startsWith("/api")) {
|
||||||
|
return handleApiProxyRequest(req, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
return handleStaticFileRequest(liveDirectory, req, res)
|
||||||
|
})
|
||||||
|
|
||||||
|
await app.listen(LISTENT_PORT)
|
||||||
|
|
||||||
|
console.log(`LISTENING on port ${LISTENT_PORT}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleStaticFileRequest(liveDirectory, req, res) {
|
||||||
|
let file = liveDirectory.get(req.path)
|
||||||
|
|
||||||
|
if (file === undefined) {
|
||||||
|
file = liveDirectory.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]
|
||||||
|
|
||||||
|
// Retrieve the file content and serve it depending on the type of content available for this file
|
||||||
|
const content = file.content
|
||||||
|
|
||||||
|
if (content instanceof Buffer) {
|
||||||
|
// Set appropriate mime-type and serve file content Buffer as response body (This means that the file content was cached in memory)
|
||||||
|
return res.type(extension).send(content)
|
||||||
|
} else {
|
||||||
|
// Set the type and stream the content as the response body (This means that the file content was NOT cached in memory)
|
||||||
|
return res.type(extension).stream(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleApiProxyRequest(request, response) {
|
||||||
|
try {
|
||||||
|
const targetURL = new URL(request.url, TARGET_HTTP)
|
||||||
|
const headers = { ...request.headers, host: targetURL.host }
|
||||||
|
|
||||||
|
// Configurar la solicitud al servidor de destino
|
||||||
|
const proxyReq = http.request({
|
||||||
|
hostname: targetURL.hostname,
|
||||||
|
port: targetURL.port || 80,
|
||||||
|
path: targetURL.pathname + targetURL.search,
|
||||||
|
method: request.method,
|
||||||
|
headers,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Manejar la respuesta del servidor de destino
|
||||||
|
proxyReq.on("response", (proxyRes) => {
|
||||||
|
response.status(proxyRes.statusCode)
|
||||||
|
|
||||||
|
// Copiar headers
|
||||||
|
Object.entries(proxyRes.headers).forEach(([key, val]) => {
|
||||||
|
response.header(key, val)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Pipe de la respuesta
|
||||||
|
proxyRes.pipe(response.stream)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Manejar errores
|
||||||
|
proxyReq.on("error", (error) => {
|
||||||
|
response.status(500).send(`Proxy error: ${error.message}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Pipe del cuerpo de la solicitud
|
||||||
|
request.stream().pipe(proxyReq)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
response.status(500).send("Internal Server Error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
79
packages/wrapper/src/index.js
Normal file
79
packages/wrapper/src/index.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { Server } from "linebridge"
|
||||||
|
import LiveDirectory from "live-directory"
|
||||||
|
import * as Setup from "./lib/setupDist"
|
||||||
|
|
||||||
|
import path from "node:path"
|
||||||
|
import fs from "node:fs"
|
||||||
|
|
||||||
|
class WebWrapper extends Server {
|
||||||
|
static disableBaseEndpoints = true
|
||||||
|
static listenPort = process.env.HTTP_LISTEN_PORT || 9999
|
||||||
|
|
||||||
|
static publicPath = path.resolve(process.cwd(), "public")
|
||||||
|
static cachePath = path.resolve(process.cwd(), ".cache")
|
||||||
|
static distManifestPath = path.resolve(this.publicPath, "manifest.json")
|
||||||
|
static distCompressedFile = "app_dist.7z"
|
||||||
|
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 onInitialize() {
|
||||||
|
if (!fs.existsSync(WebWrapper.publicPath)) {
|
||||||
|
console.log("WebWrapper public path does not exist, creating...")
|
||||||
|
fs.mkdirSync(WebWrapper.publicPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(WebWrapper.distManifestPath)) {
|
||||||
|
console.log(`App dist manifest does not exist, setting up...`)
|
||||||
|
|
||||||
|
await Setup.setupLatestRelease({
|
||||||
|
repository: WebWrapper.repoName,
|
||||||
|
distCompressedFile: WebWrapper.distCompressedFile,
|
||||||
|
destinationPath: WebWrapper.publicPath,
|
||||||
|
cachePath: WebWrapper.cachePath,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
global.staticLiveDirectory = new LiveDirectory(WebWrapper.publicPath, {
|
||||||
|
static: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Boot(WebWrapper)
|
26
packages/wrapper/src/lib/downloadFile.js
Normal file
26
packages/wrapper/src/lib/downloadFile.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import fs from "node:fs"
|
||||||
|
import path from "node:path"
|
||||||
|
|
||||||
|
import axios from "axios"
|
||||||
|
|
||||||
|
export default async function downloadFile(url, destination, filename) {
|
||||||
|
// check if bundle exists
|
||||||
|
if (fs.existsSync(path.join(destination, filename))) {
|
||||||
|
fs.unlinkSync(path.join(destination, filename))
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Downloading file > ", url)
|
||||||
|
|
||||||
|
const response = await axios.get(url, {
|
||||||
|
responseType: "stream",
|
||||||
|
})
|
||||||
|
|
||||||
|
const writer = fs.createWriteStream(path.join(destination, filename))
|
||||||
|
|
||||||
|
response.data.pipe(writer)
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
writer.on("finish", resolve)
|
||||||
|
writer.on("error", reject)
|
||||||
|
})
|
||||||
|
}
|
16
packages/wrapper/src/lib/extractCompressedFile.js
Normal file
16
packages/wrapper/src/lib/extractCompressedFile.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import path from "node:path"
|
||||||
|
import _7z from "7zip-min"
|
||||||
|
|
||||||
|
export default async function extractCompressedFile(from, to) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log(`Extracting file [${from}] > [${to}]`)
|
||||||
|
|
||||||
|
_7z.unpack(path.join(from), path.resolve(to), (err) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
resolve(global.distPath)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
87
packages/wrapper/src/lib/setupDist.js
Executable file
87
packages/wrapper/src/lib/setupDist.js
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
import fs from "node:fs"
|
||||||
|
import path from "node:path"
|
||||||
|
import _7z from "7zip-min"
|
||||||
|
import { Octokit } from "@octokit/rest"
|
||||||
|
|
||||||
|
import downloadFile from "./downloadFile"
|
||||||
|
import extractCompressedFile from "./extractCompressedFile"
|
||||||
|
|
||||||
|
const octokit = new Octokit()
|
||||||
|
|
||||||
|
async function getLatestReleaseFromGithub(repoStr) {
|
||||||
|
console.log("Getting latest release from github...")
|
||||||
|
|
||||||
|
const release = await octokit.repos.getLatestRelease({
|
||||||
|
owner: repoStr.split("/")[0],
|
||||||
|
repo: repoStr.split("/")[1],
|
||||||
|
})
|
||||||
|
|
||||||
|
return release.data
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findBundleFromRelease(release, distCompressedFile) {
|
||||||
|
const bundle = release.assets.find(
|
||||||
|
(asset) => asset.name === distCompressedFile,
|
||||||
|
)
|
||||||
|
|
||||||
|
return bundle
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setupLatestRelease({
|
||||||
|
cachePath,
|
||||||
|
destinationPath,
|
||||||
|
repository,
|
||||||
|
distCompressedFile,
|
||||||
|
}) {
|
||||||
|
// create cache folder
|
||||||
|
if (!fs.existsSync(cachePath)) {
|
||||||
|
fs.mkdirSync(cachePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create dist folder
|
||||||
|
if (!fs.existsSync(destinationPath)) {
|
||||||
|
fs.mkdirSync(destinationPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
const release = await getLatestReleaseFromGithub(repository)
|
||||||
|
|
||||||
|
console.log(`Latest release: > ${release.tag_name} [${release.url}]`)
|
||||||
|
|
||||||
|
const bundle = await findBundleFromRelease(release, distCompressedFile)
|
||||||
|
|
||||||
|
console.log(`Bundle: > ${bundle.name} [${bundle.browser_download_url}]`)
|
||||||
|
|
||||||
|
// wirte a manifest file with bundle version and other info
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(destinationPath, "manifest.json"),
|
||||||
|
JSON.stringify({
|
||||||
|
version: release.tag_name,
|
||||||
|
date: release.published_at,
|
||||||
|
stable: !release.prerelease,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
await downloadFile(
|
||||||
|
bundle.browser_download_url,
|
||||||
|
cachePath,
|
||||||
|
distCompressedFile,
|
||||||
|
)
|
||||||
|
|
||||||
|
await extractCompressedFile(
|
||||||
|
path.join(cachePath, distCompressedFile),
|
||||||
|
destinationPath,
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log(`Bundle extracted to > ${destinationPath}`)
|
||||||
|
|
||||||
|
// delete cache folder
|
||||||
|
if (fs.existsSync(cachePath)) {
|
||||||
|
fs.rmdirSync(cachePath, { recursive: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
downloadBundle: downloadFile,
|
||||||
|
extractBundle: extractCompressedFile,
|
||||||
|
setupLatestRelease,
|
||||||
|
}
|
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@comty/web-wrapper",
|
|
||||||
"version": "0.60.3",
|
|
||||||
"main": "./src/index.js",
|
|
||||||
"license": "MIT",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "hermes-node ./src/index.js"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"7zip-min": "^1.4.3",
|
|
||||||
"@octokit/rest": "^19.0.4",
|
|
||||||
"axios": "^0.27.2",
|
|
||||||
"chalk": "4.1.2",
|
|
||||||
"cors": "2.8.5",
|
|
||||||
"dotenv": "^16.0.3",
|
|
||||||
"express": "^4.18.1",
|
|
||||||
"http-proxy-middleware": "^2.0.6",
|
|
||||||
"module-alias": "^2.2.3",
|
|
||||||
"pm2": "^5.3.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@ragestudio/hermes": "^0.1.1"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
module.exports = " _ \r\n | | \r\n ___ ___ _ __ ___ | |_ _ _ \r\n \/ __\/ _ \\| \'_ ` _ \\| __| | | |\r\n | (_| (_) | | | | | | |_| |_| |\r\n \\___\\___\/|_| |_| |_|\\__|\\__, |\r\n __\/ |\r\n |___\/ "
|
|
@ -1,22 +0,0 @@
|
|||||||
require("dotenv").config()
|
|
||||||
|
|
||||||
const path = require("path")
|
|
||||||
const moduleAlias = require("module-alias")
|
|
||||||
|
|
||||||
global.packagejson = require("../package.json")
|
|
||||||
global.__root = path.resolve(__dirname)
|
|
||||||
global.isProduction = process.env.NODE_ENV === "production"
|
|
||||||
global.remoteRepo = "ragestudio/comty"
|
|
||||||
global.cachePath = path.join(process.cwd(), "cache")
|
|
||||||
global.distPath = path.join(process.cwd(), "dist")
|
|
||||||
|
|
||||||
const aliases = {
|
|
||||||
"@shared-classes": path.resolve(__dirname, "_shared/classes"),
|
|
||||||
"@shared-lib": path.resolve(__dirname, "_shared/lib"),
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!global.isProduction) {
|
|
||||||
aliases["@shared-classes"] = path.resolve(__dirname, "shared-classes")
|
|
||||||
}
|
|
||||||
|
|
||||||
moduleAlias.addAliases(aliases)
|
|
@ -1,341 +0,0 @@
|
|||||||
require("./globals")
|
|
||||||
|
|
||||||
const fs = require("fs")
|
|
||||||
const path = require("path")
|
|
||||||
const express = require("express")
|
|
||||||
const cors = require("cors")
|
|
||||||
const chalk = require("chalk")
|
|
||||||
const { spawn } = require("child_process")
|
|
||||||
|
|
||||||
const getInternalIp = require("./lib/getInternalIp")
|
|
||||||
const comtyAscii = require("./ascii")
|
|
||||||
|
|
||||||
const useLogger = require("./lib/useLogger")
|
|
||||||
const { createProxyMiddleware } = require("http-proxy-middleware")
|
|
||||||
|
|
||||||
const { setupLatestRelease } = require("./lib/setupDist")
|
|
||||||
|
|
||||||
const developmentServers = [
|
|
||||||
{
|
|
||||||
name: "WebAPP",
|
|
||||||
color: "bgRed",
|
|
||||||
cwd: path.resolve(global.__root, "../../app"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "MainAPI",
|
|
||||||
color: "bgBlue",
|
|
||||||
cwd: path.resolve(global.__root, "../../server"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ChatAPI",
|
|
||||||
color: "bgMagenta",
|
|
||||||
cwd: path.resolve(global.__root, "../../chat_server"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "MarketplaceAPI",
|
|
||||||
color: "bgCyan",
|
|
||||||
cwd: path.resolve(global.__root, "../../marketplace_server"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "MusicAPI",
|
|
||||||
color: "bgGreen",
|
|
||||||
cwd: path.resolve(global.__root, "../../music_server")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "FileAPI",
|
|
||||||
color: "bgYellow",
|
|
||||||
cwd: path.resolve(global.__root, "../../file_server"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "SyncAPI",
|
|
||||||
color: "bgMagenta",
|
|
||||||
cwd: path.resolve(global.__root, "../../sync_server"),
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const ApiServers = [
|
|
||||||
{
|
|
||||||
name: "main",
|
|
||||||
remote: ({
|
|
||||||
address,
|
|
||||||
protocol,
|
|
||||||
port
|
|
||||||
} = {}) => `${protocol ?? "http"}://${address ?? process.env.LOCALHOST}:${port ?? 3010}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "chat",
|
|
||||||
remote: ({
|
|
||||||
address,
|
|
||||||
protocol,
|
|
||||||
port
|
|
||||||
} = {}) => `${protocol ?? "http"}://${address ?? process.env.LOCALHOST}:${port ?? 3020}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "livestreaming",
|
|
||||||
remote: ({
|
|
||||||
address,
|
|
||||||
protocol,
|
|
||||||
port
|
|
||||||
} = {}) => `${protocol ?? "http"}://${address ?? process.env.LOCALHOST}:${port ?? 3030}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "marketplace",
|
|
||||||
remote: ({
|
|
||||||
address,
|
|
||||||
protocol,
|
|
||||||
port
|
|
||||||
} = {}) => `${protocol ?? "http"}://${address ?? process.env.LOCALHOST}:${port ?? 3040}`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "music",
|
|
||||||
remote: ({
|
|
||||||
address,
|
|
||||||
protocol,
|
|
||||||
port
|
|
||||||
} = {}) => `${protocol ?? "http"}://${address ?? process.env.LOCALHOST}:${port ?? 3050}`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "files",
|
|
||||||
remote: ({
|
|
||||||
address,
|
|
||||||
protocol,
|
|
||||||
port
|
|
||||||
} = {}) => `${protocol ?? "http"}://${address ?? process.env.LOCALHOST}:${port ?? 3060}`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "sync",
|
|
||||||
remote: ({
|
|
||||||
address,
|
|
||||||
protocol,
|
|
||||||
port
|
|
||||||
} = {}) => `${protocol ?? "http"}://${address ?? process.env.LOCALHOST}:${port ?? 3070}`
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
class Main {
|
|
||||||
static checkDistIntegrity() {
|
|
||||||
// check if dist folder exists
|
|
||||||
if (!fs.existsSync(global.distPath)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: check the dist checksum with oficial server checksum
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
static fetchDistManifest() {
|
|
||||||
if (!fs.existsSync(global.distPath)) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const pkgPath = path.join(global.distPath, "manifest.json")
|
|
||||||
|
|
||||||
if (!fs.existsSync(pkgPath)) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const pkg = require(pkgPath)
|
|
||||||
|
|
||||||
return pkg
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(process) {
|
|
||||||
this.process = process
|
|
||||||
this.args = this.getArgs()
|
|
||||||
|
|
||||||
this.registerExitHandlers()
|
|
||||||
this.initialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
initialize = async () => {
|
|
||||||
console.clear()
|
|
||||||
console.log(comtyAscii)
|
|
||||||
console.log(`${chalk.bgBlue(`Running Wrapper`)} ${chalk.bgMagenta(`[v${global.packagejson.version}]`)}`)
|
|
||||||
|
|
||||||
this.internalIp = await getInternalIp()
|
|
||||||
|
|
||||||
this.webapp_port = this.args.web_port ?? 9000
|
|
||||||
this.api_port = this.args.api_proxy_port ?? 5000
|
|
||||||
|
|
||||||
if (this.args.dev === true) {
|
|
||||||
console.log(`🔧 Running in ${chalk.bgYellow("DEVELOPMENT")} mode \n\n`)
|
|
||||||
|
|
||||||
//this.runDevelopmentServers()
|
|
||||||
this.runDevelopmentScript()
|
|
||||||
this.initializeAPIProxyServer()
|
|
||||||
|
|
||||||
return this
|
|
||||||
} else {
|
|
||||||
if (!Main.checkDistIntegrity()) {
|
|
||||||
await setupLatestRelease()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.args["no-web"]) {
|
|
||||||
this.initializeWebAppServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.initializeAPIProxyServer()
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
runDevelopmentScript = async () => {
|
|
||||||
const devScript = spawn("npm", ["run", "dev"], {
|
|
||||||
cwd: path.resolve(global.__root, "../../../"),
|
|
||||||
shell: true,
|
|
||||||
stdio: "inherit"
|
|
||||||
})
|
|
||||||
|
|
||||||
devScript.on("exit", (code) => {
|
|
||||||
console.log(`🔧 ${chalk.bgYellow("WebAPP")} exited with code ${code}`)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
runDevelopmentServers = async () => {
|
|
||||||
this.dev_servers = []
|
|
||||||
|
|
||||||
// start all development servers
|
|
||||||
for (let i = 0; i < developmentServers.length; i++) {
|
|
||||||
const server = developmentServers[i]
|
|
||||||
|
|
||||||
console.log(`🔧 Starting ${chalk.bgYellow(server.name)}...`)
|
|
||||||
|
|
||||||
const serverProcess = spawn("npm", ["run", "dev"], {
|
|
||||||
cwd: server.cwd,
|
|
||||||
shell: true
|
|
||||||
})
|
|
||||||
|
|
||||||
let chalkInstance = chalk[server.color]
|
|
||||||
|
|
||||||
if (typeof chalkInstance === undefined) {
|
|
||||||
chalkInstance = chalk.bgWhite
|
|
||||||
}
|
|
||||||
|
|
||||||
// log output of server
|
|
||||||
serverProcess.stdout.on("data", (data) => {
|
|
||||||
console.log(`${chalkInstance(`[${server.name}]`)} ${data.toString()}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
serverProcess.on("exit", (code) => {
|
|
||||||
console.log(`🔧 ${chalk.bgYellow(server.name)} exited with code ${code}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
this.dev_servers.push({
|
|
||||||
name: server.name,
|
|
||||||
process: serverProcess
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
registerExitHandlers() {
|
|
||||||
this.process.on("exit", this.onExit)
|
|
||||||
this.process.on("SIGINT", this.onExit)
|
|
||||||
this.process.on("SIGUSR1", this.onExit)
|
|
||||||
this.process.on("SIGUSR2", this.onExit)
|
|
||||||
this.process.on("uncaughtException", this.onExit)
|
|
||||||
}
|
|
||||||
|
|
||||||
onExit = async () => {
|
|
||||||
console.clear()
|
|
||||||
console.log(comtyAscii)
|
|
||||||
console.log(`\n\nClosing wrapper... \n\n`)
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
console.log(`Wrapper did not close in time, forcefully closing...`)
|
|
||||||
process.exit(0)
|
|
||||||
}, 5000)
|
|
||||||
|
|
||||||
if (Array.isArray(this.dev_servers)) {
|
|
||||||
for await (const server of this.dev_servers) {
|
|
||||||
console.log(`Killing ${chalk.bgYellow(server.name)}...`)
|
|
||||||
|
|
||||||
server.process.kill()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return process.exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
getArgs = () => {
|
|
||||||
let args = {}
|
|
||||||
|
|
||||||
for (let i = 0; i < this.process.argv.length; i++) {
|
|
||||||
const arg = this.process.argv[i]
|
|
||||||
|
|
||||||
if (arg.startsWith("--")) {
|
|
||||||
const argName = arg.replace("--", "")
|
|
||||||
const argValue = this.process.argv[i + 1]
|
|
||||||
|
|
||||||
args[argName] = argValue ?? true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return args
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeWebAppServer = async () => {
|
|
||||||
this.webapp_server = express()
|
|
||||||
|
|
||||||
this.webapp_server.use(cors({
|
|
||||||
origin: "*",
|
|
||||||
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
|
|
||||||
preflightContinue: true,
|
|
||||||
optionsSuccessStatus: 204
|
|
||||||
}))
|
|
||||||
|
|
||||||
if (!this.forwardAppPort) {
|
|
||||||
this.webapp_server.use(express.static(global.distPath))
|
|
||||||
|
|
||||||
this.webapp_server.get("*", (req, res) => {
|
|
||||||
return res.sendFile(path.join(global.distPath, "index.html"))
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.webapp_server.use(createProxyMiddleware({
|
|
||||||
target: `http://${this.internalIp}:${this.forwardAppPort}`,
|
|
||||||
changeOrigin: true,
|
|
||||||
ws: true,
|
|
||||||
pathRewrite: {
|
|
||||||
"^/": ""
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
this.webapp_server.listen(this.webapp_port)
|
|
||||||
|
|
||||||
console.log(`🌐 WEB-APP Listening on > `, `${this.internalIp}:${this.webapp_port}`)
|
|
||||||
|
|
||||||
return this.webapp_server
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeAPIProxyServer = async () => {
|
|
||||||
this.apiproxy_server = express()
|
|
||||||
|
|
||||||
this.apiproxy_server.use(useLogger)
|
|
||||||
|
|
||||||
ApiServers.forEach((server) => {
|
|
||||||
const remote = server.remote({
|
|
||||||
address: this.internalIp,
|
|
||||||
protocol: this.forceApiHttps ? "https" : "http",
|
|
||||||
})
|
|
||||||
|
|
||||||
this.apiproxy_server.use(`/${server.name}`, createProxyMiddleware({
|
|
||||||
target: `${remote}`,
|
|
||||||
changeOrigin: true,
|
|
||||||
ws: true,
|
|
||||||
pathRewrite: {
|
|
||||||
[`^/${server.name}`]: ""
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
this.apiproxy_server.listen(this.api_port)
|
|
||||||
|
|
||||||
console.log(`🌐 API-PROXY Listening on >`, `${this.internalIp}:${this.api_port}`)
|
|
||||||
|
|
||||||
return this.apiproxy_server
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new Main(process)
|
|
@ -1,12 +0,0 @@
|
|||||||
const dns = require("dns")
|
|
||||||
const os = require("os")
|
|
||||||
|
|
||||||
module.exports = () => new Promise((resolve, reject) => {
|
|
||||||
dns.lookup(os.hostname(), (err, address, family) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(address)
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,117 +0,0 @@
|
|||||||
const fs = require("fs")
|
|
||||||
const path = require("path")
|
|
||||||
const axios = require("axios")
|
|
||||||
const _7z = require("7zip-min")
|
|
||||||
const { Octokit } = require("@octokit/rest")
|
|
||||||
|
|
||||||
const octokit = new Octokit({
|
|
||||||
// auth: process.env.GITHUB_TOKEN
|
|
||||||
})
|
|
||||||
|
|
||||||
async function getLatestReleaseFromGithub() {
|
|
||||||
console.log("Getting latest release from github...")
|
|
||||||
|
|
||||||
const release = await octokit.repos.getLatestRelease({
|
|
||||||
owner: global.remoteRepo.split("/")[0],
|
|
||||||
repo: global.remoteRepo.split("/")[1]
|
|
||||||
})
|
|
||||||
|
|
||||||
return release.data
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getBundleFromRelease(release) {
|
|
||||||
const bundle = release.assets.find(asset => asset.name === "app_dist.7z")
|
|
||||||
|
|
||||||
return bundle
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getLatestReleaseBundleFromGithub() {
|
|
||||||
console.log("Getting latest release bundle from github...")
|
|
||||||
|
|
||||||
const release = await getLatestReleaseFromGithub()
|
|
||||||
|
|
||||||
const bundle = release.data.assets.find(asset => asset.name === "app_dist.7z")
|
|
||||||
|
|
||||||
return bundle
|
|
||||||
}
|
|
||||||
|
|
||||||
async function downloadBundle(bundle) {
|
|
||||||
// check if bundle exists
|
|
||||||
if (fs.existsSync(path.join(global.cachePath, "app_dist.7z"))) {
|
|
||||||
fs.unlinkSync(path.join(global.cachePath, "app_dist.7z"))
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Downloading bundle...")
|
|
||||||
|
|
||||||
const response = await axios.get(bundle.browser_download_url, {
|
|
||||||
responseType: "stream"
|
|
||||||
})
|
|
||||||
|
|
||||||
const writer = fs.createWriteStream(path.join(global.cachePath, "app_dist.7z"))
|
|
||||||
|
|
||||||
response.data.pipe(writer)
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
writer.on("finish", resolve)
|
|
||||||
writer.on("error", reject)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function extractBundle() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
console.log("Extracting bundle...")
|
|
||||||
|
|
||||||
_7z.unpack(path.join(global.cachePath, "app_dist.7z"), path.resolve(global.distPath, ".."), (err) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err)
|
|
||||||
} else {
|
|
||||||
resolve(global.distPath)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function setupLatestRelease() {
|
|
||||||
// create cache folder
|
|
||||||
if (!fs.existsSync(global.cachePath)) {
|
|
||||||
fs.mkdirSync(global.cachePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// create dist folder
|
|
||||||
if (!fs.existsSync(global.distPath)) {
|
|
||||||
fs.mkdirSync(global.distPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
const release = await getLatestReleaseFromGithub()
|
|
||||||
|
|
||||||
const bundle = await getBundleFromRelease(release)
|
|
||||||
|
|
||||||
// wirte a manifest file with bundle version and other info
|
|
||||||
fs.writeFileSync(path.join(global.distPath, "manifest.json"), JSON.stringify(
|
|
||||||
{
|
|
||||||
version: release.tag_name,
|
|
||||||
date: release.published_at,
|
|
||||||
stable: !release.prerelease,
|
|
||||||
}
|
|
||||||
))
|
|
||||||
|
|
||||||
await downloadBundle(bundle)
|
|
||||||
|
|
||||||
const bundlePath = await extractBundle()
|
|
||||||
|
|
||||||
console.log(`Bundle extracted to ${bundlePath}`)
|
|
||||||
|
|
||||||
console.log("Cleaning up...")
|
|
||||||
|
|
||||||
// delete cache folder
|
|
||||||
if (fs.existsSync(global.cachePath)) {
|
|
||||||
fs.rmdirSync(global.cachePath, { recursive: true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getLatestReleaseBundleFromGithub,
|
|
||||||
downloadBundle,
|
|
||||||
extractBundle,
|
|
||||||
setupLatestRelease,
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
// just works with express
|
|
||||||
module.exports = (req, res, next) => {
|
|
||||||
const startHrTime = process.hrtime()
|
|
||||||
|
|
||||||
res.on("finish", () => {
|
|
||||||
const elapsedHrTime = process.hrtime(startHrTime)
|
|
||||||
const elapsedTimeInMs = elapsedHrTime[0] * 1000 + elapsedHrTime[1] / 1e6
|
|
||||||
|
|
||||||
res._responseTimeMs = elapsedTimeInMs
|
|
||||||
|
|
||||||
// cut req.url if is too long
|
|
||||||
if (req.url.length > 100) {
|
|
||||||
req.url = req.url.substring(0, 100) + "..."
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`${req.method} ${res._status_code ?? res.statusCode ?? 200} ${req.url} ${elapsedTimeInMs}ms`)
|
|
||||||
})
|
|
||||||
|
|
||||||
next()
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user