diff --git a/package.json b/package.json
index bf9e245b..c580251b 100755
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"scripts": {
"postinstall": "npm rebuild @tensorflow/tfjs-node --build-from-source && node ./scripts/postinstall.js",
"release": "node ./scripts/release.js",
+ "wrapper:dev": "node ./packages/wrapper/src/index.js --dev",
"dev": "concurrently -k -n Client,Server,MarketplaceServer,ChatServer,FileServer,MusicServer -c bgCyan,auto \"yarn dev:client\" \"yarn dev:server\" \"yarn dev:marketplace_server\" \"yarn dev:chat_server\" \"yarn dev:file_server\" \"yarn dev:music_server\"",
"dev:file_server": "cd packages/file_server && yarn dev",
"dev:music_server": "cd packages/music_server && yarn dev",
@@ -31,4 +32,4 @@
"pm2": "5.3.0"
},
"version": "0.49.0"
-}
\ No newline at end of file
+}
diff --git a/packages/app/constants/settings/tap_share/index.jsx b/packages/app/constants/settings/tap_share/index.jsx
index 5ac55125..b3423b21 100644
--- a/packages/app/constants/settings/tap_share/index.jsx
+++ b/packages/app/constants/settings/tap_share/index.jsx
@@ -263,26 +263,37 @@ const OpenTagEditor = ({ tag, onFinish = () => app.navigation.softReload() } = {
const TapShareRender = () => {
return
+ {
+ !app.cores.nfc.scanning && app.isMobile &&
+ }
+
Registered Tags
-
- You can quickly edit your tags by tapping them.
-
-
+ {
+ app.cores.nfc.scanning &&
+ You can quickly edit your tags by tapping them.
+
+ }
-
}
- onClick={() => OpenTagEditor()}
- >
- Add new
-
+ {
+ app.isMobile &&
}
+ onClick={() => OpenTagEditor()}
+ >
+ Add new
+
+ }
}
diff --git a/packages/app/constants/settings/tap_share/steps/tag_writter/index.jsx b/packages/app/constants/settings/tap_share/steps/tag_writter/index.jsx
index 86cc261b..ef54ea63 100644
--- a/packages/app/constants/settings/tap_share/steps/tag_writter/index.jsx
+++ b/packages/app/constants/settings/tap_share/steps/tag_writter/index.jsx
@@ -22,13 +22,6 @@ export default (props) => {
return false
}
- const nfcInstance = app.cores.nfc.instance()
-
- if (!nfcInstance) {
- setError(NFC_ERRORS.NFC_NOT_AVAILABLE)
- return false
- }
-
setError(null)
setLoading(true)
@@ -40,7 +33,7 @@ export default (props) => {
return false
}
- nfcInstance.write({
+ app.cores.nfc.writeNdef({
records: [{
recordType: "url",
data: context.values.endpoint_url
diff --git a/packages/app/src/App.jsx b/packages/app/src/App.jsx
index 2fdbb019..c04e1baa 100755
--- a/packages/app/src/App.jsx
+++ b/packages/app/src/App.jsx
@@ -66,7 +66,6 @@ import loadable from "@loadable/component"
import { StatusBar, Style } from "@capacitor/status-bar"
import { App as CapacitorApp } from "@capacitor/app"
-import { SplashScreen } from "@capacitor/splash-screen"
import { CapacitorUpdater } from "@capgo/capacitor-updater"
import SessionModel from "models/session"
@@ -98,6 +97,8 @@ import * as Router from "./router"
import "theme/index.less"
+console.log(`REACT VERSION: ${React.version}`)
+
CapacitorUpdater.notifyAppReady()
class ComtyApp extends React.Component {
@@ -118,15 +119,10 @@ class ComtyApp extends React.Component {
}
static splashAwaitEvent = "app.initialization.finish"
-
static async initialize() {
- SplashScreen.show({
- autoHide: false,
- })
-
- window.app.splash = SplashScreen
window.app.version = config.package.version
window.app.message = antd.message
+ window.app.isCapacitor = window.navigator.userAgent === "capacitor"
window.localStorage.setItem("last_version", window.app.version)
@@ -492,8 +488,6 @@ class ComtyApp extends React.Component {
this.setState({ initialized: true })
Utils.handleOpenDevTools()
-
- SplashScreen.hide()
}
onRuntimeStateUpdate = (state) => {
diff --git a/packages/app/src/components/PagePanels/components/NavMenu/index.jsx b/packages/app/src/components/PagePanels/components/NavMenu/index.jsx
index ff4e389b..33820990 100644
--- a/packages/app/src/components/PagePanels/components/NavMenu/index.jsx
+++ b/packages/app/src/components/PagePanels/components/NavMenu/index.jsx
@@ -2,8 +2,6 @@ import React from "react"
import classnames from "classnames"
import * as antd from "antd"
-import { createIconRender } from "components/Icons"
-
import "./index.less"
const NavMenu = (props) => {
diff --git a/packages/app/src/cores/haptics/haptics.core.js b/packages/app/src/cores/haptics/haptics.core.js
index 9f40d70d..b21b50f5 100644
--- a/packages/app/src/cores/haptics/haptics.core.js
+++ b/packages/app/src/cores/haptics/haptics.core.js
@@ -1,4 +1,5 @@
import Core from "evite/src/core"
+import { Haptics } from "@capacitor/haptics"
const vibrationPatterns = {
light: [10],
@@ -19,6 +20,10 @@ export default class HapticsCore extends Core {
}
async onInitialize() {
+ if (window.navigator.userAgent === "capacitor") {
+ navigator.vibrate = this.nativeVibrate
+ }
+
document.addEventListener("click", this.handleClickEvent)
}
@@ -27,6 +32,18 @@ export default class HapticsCore extends Core {
vibrate: this.vibrate.bind(this),
}
+ nativeVibrate = (pattern) => {
+ if (!Array.isArray(pattern)) {
+ pattern = [pattern]
+ }
+
+ for (let i = 0; i < pattern.length; i++) {
+ Haptics.vibrate({
+ duration: pattern[i],
+ })
+ }
+ }
+
handleClickEvent = (event) => {
const button = event.target.closest("button") || event.target.closest(".ant-btn")
diff --git a/packages/app/src/cores/nfc/nfc.core.js b/packages/app/src/cores/nfc/nfc.core.js
index d8aea5cc..759dd354 100644
--- a/packages/app/src/cores/nfc/nfc.core.js
+++ b/packages/app/src/cores/nfc/nfc.core.js
@@ -1,40 +1,137 @@
import Core from "evite/src/core"
import TapShareDialog from "components/TapShare/Dialog"
-import { Nfc, NfcUtils, NfcTagTechType } from "@capawesome-team/capacitor-nfc"
+
+const RecordTypes = {
+ "T": "text",
+ "U": "url"
+}
+
+function decodePayload(record) {
+ let recordType = nfc.bytesToString(record.type)
+
+ let payload = {
+ recordId: nfc.bytesToHexString(record.id),
+ recordType: RecordTypes[recordType],
+ data: null
+ }
+
+ switch (recordType) {
+ case "T": {
+ let langCodeLength = record.payload[0]
+
+ payload.data = record.payload.slice((1 + langCodeLength), record.payload.length)
+
+ payload.data = nfc.bytesToString(text)
+
+ break
+ }
+ case "U": {
+ let identifierCode = record.payload.shift()
+
+ payload.data = nfc.bytesToString(record.payload)
+
+ switch (identifierCode) {
+ case 4: {
+ payload.data = `https://${payload.data}`
+ break
+ }
+ case 3: {
+ payload.data = `http://${payload.data}`
+ break
+ }
+ }
+
+ break
+ }
+ default: {
+ payload.data = nfc.bytesToString(record.payload)
+ break
+ }
+ }
+
+ return payload
+}
+
+function resolveSerialNumber(tag) {
+ let serialNumber = null
+
+ serialNumber = nfc.bytesToHexString(tag.id)
+
+ // transform serialNumber to contain a ":" every 2 bytes
+ serialNumber = serialNumber.replace(/(.{2})/g, "$1:")
+
+ // remove the last :
+ serialNumber = serialNumber.slice(0, -1)
+
+ return serialNumber
+}
+
+function parseNdefMessage(ndefMessage) {
+ let message = []
+
+ ndefMessage.forEach((ndefRecord) => {
+ message.push(decodePayload(ndefRecord))
+ })
+
+ return message
+}
export default class NFC extends Core {
static refName = "NFC"
static namespace = "nfc"
+ isNativeMode = false
+
instance = null
subscribers = []
public = {
- incompatible: null,
+ incompatible: true,
scanning: false,
- startScanning: this.startScanning.bind(this),
+ writeNdef: this.writeNdef.bind(this),
instance: function () { return this.instance }.bind(this),
subscribe: this.subscribe.bind(this),
unsubscribe: this.unsubscribe.bind(this),
}
- async onInitialize() {
- if ("NDEFReader" in window === false) {
- return this.public.incompatible = true
+ subscribe(callback) {
+ // check if scan service is available, if not try to initialize
+ if (this.public.scanning === false) {
+ this.startScanning()
}
- this.instance = new NDEFReader()
+ this.subscribers.push(callback)
+ }
- this.startScanning()
+ unsubscribe(callback) {
+ this.subscribers = this.subscribers.filter((subscriber) => {
+ return subscriber !== callback
+ })
+ }
+
+ async onInitialize() {
+ if (window.nfc) {
+ this.instance = window.nfc
+
+ this.isNativeMode = true
+
+ return this.startNativeScanning()
+ }
+
+ if ("NDEFReader" in window) {
+ this.instance = new NDEFReader()
+
+ return this.startScanning()
+ }
+
+ return this.public.incompatible = true
}
async startScanning() {
try {
- //await navigator.permissions.query({ name: "nfc" })
-
- this.instance.scan()
+ await this.instance.scan()
this.public.scanning = true
this.public.incompatible = false
@@ -48,23 +145,11 @@ export default class NFC extends Core {
}
}
- subscribe(callback) {
- // check if scan service is available, if not try to initialize
- if (this.public.scanning === false) {
- this.startScanning()
- }
+ startNativeScanning() {
+ this.public.scanning = true
+ this.public.incompatible = false
- this.subscribers.push(callback)
-
- console.debug(`[NFC] SUBSCRIBED >`, this.subscribers.length)
- }
-
- unsubscribe(callback) {
- this.subscribers = this.subscribers.filter((subscriber) => {
- return subscriber !== callback
- })
-
- console.debug(`[NFC] UNSUBSCRIBED >`, this.subscribers.length)
+ return this.registerNativeEventListeners()
}
handleRead(tag) {
@@ -75,8 +160,6 @@ export default class NFC extends Core {
subscriber(null, tag)
})
- console.log(this.subscribers)
-
if (this.subscribers.length === 0) {
if (tag.message.records?.length > 0) {
// open dialog
@@ -89,6 +172,32 @@ export default class NFC extends Core {
}
}
+ handleNativeRead(tag) {
+ console.debug(`[NFC] NATIVE READ >`, tag)
+
+ tag.serialNumber = resolveSerialNumber(tag)
+
+ if (tag.ndefMessage) {
+ tag.message = {}
+ tag.message.records = parseNdefMessage(tag.ndefMessage)
+ }
+
+ this.subscribers.forEach((subscriber) => {
+ subscriber(null, tag)
+ })
+
+ if (this.subscribers.length === 0 && tag.message?.records) {
+ if (tag.message.records?.length > 0) {
+ // open dialog
+ app.DrawerController.open("nfc_card_dialog", TapShareDialog, {
+ componentProps: {
+ tag: tag,
+ }
+ })
+ }
+ }
+ }
+
handleError(error) {
this.subscribers.forEach((subscriber) => {
subscriber(error, null)
@@ -99,4 +208,57 @@ export default class NFC extends Core {
this.instance.addEventListener("reading", this.handleRead.bind(this))
this.instance.addEventListener("error", this.handleError.bind(this))
}
+
+ registerNativeEventListeners() {
+ nfc.addTagDiscoveredListener(
+ (e) => this.handleNativeRead(e.tag),
+ () => {
+ this.public.scanning = true
+ this.public.incompatible = false
+ },
+ this.handleError
+ )
+
+ nfc.addNdefListener(
+ (e) => this.handleNativeRead(e.tag),
+ () => {
+ this.public.scanning = true
+ this.public.incompatible = false
+ },
+ this.handleError
+ )
+ }
+
+ async writeNdef(payload, options) {
+ console.debug(`[NFC] WRITE >`, payload)
+
+ if (!this.isNativeMode) {
+ return this.instance.write(payload, options)
+ }
+
+ let message = []
+
+ const { records } = payload
+
+ if (!Array.isArray(records)) {
+ throw new Error("records must be an array")
+ }
+
+ for (const record of records) {
+ switch (record.recordType) {
+ case "text": {
+ message.push(ndef.textRecord(record.data))
+ break
+ }
+ case "url": {
+ message.push(ndef.uriRecord(record.data))
+ break
+ }
+ }
+ }
+
+ return await new Promise((resolve, reject) => {
+ this.instance.write(message, resolve, reject)
+ })
+ }
}
\ No newline at end of file
diff --git a/packages/comty.js/src/remotes.js b/packages/comty.js/src/remotes.js
index 486f3f91..9f431256 100644
--- a/packages/comty.js/src/remotes.js
+++ b/packages/comty.js/src/remotes.js
@@ -1,4 +1,10 @@
function composeRemote(path) {
+ if (typeof window !== "undefined") {
+ if (window.localStorage.getItem("comty:use_indev") || window.location.hostname === "indev.comty.app") {
+ return envOrigins["indev"][path]
+ }
+ }
+
return envOrigins[process.env.NODE_ENV ?? "production"][path]
}
@@ -19,6 +25,14 @@ const envOrigins = {
music: `http://${getCurrentHostname()}:3050`,
files: `http://${getCurrentHostname()}:3060`,
},
+ "indev": {
+ default: `https://indev_api.comty.app/default`,
+ chat: `https://indev_api.comty.app/chat`,
+ livestreaming: `https://indev_api.comty.app/livestreaming`,
+ marketplace: `https://indev_api.comty.app/marketplace`,
+ music: `https://indev_api.comty.app/music`,
+ files: `https://indev_api.comty.app/files`,
+ },
"production": {
default: "https://api.comty.app",
chat: `https://chat_api.comty.app`,
diff --git a/packages/wrapper/package.json b/packages/wrapper/package.json
index bdb48a58..d500700c 100755
--- a/packages/wrapper/package.json
+++ b/packages/wrapper/package.json
@@ -9,12 +9,16 @@
"dependencies": {
"7zip-min": "^1.4.3",
"@octokit/rest": "^19.0.4",
- "cors": "2.8.5",
"axios": "^0.27.2",
+ "chalk": "4.1.2",
+ "cors": "2.8.5",
"dotenv": "^16.0.3",
- "express": "^4.18.1"
+ "express": "^4.18.1",
+ "http-proxy-middleware": "^2.0.6",
+ "module-alias": "^2.2.3",
+ "pm2": "^5.3.0"
},
"devDependencies": {
"corenode": "^0.28.26"
}
-}
\ No newline at end of file
+}
diff --git a/packages/wrapper/Dockerfile b/packages/wrapper/src/Dockerfile
similarity index 100%
rename from packages/wrapper/Dockerfile
rename to packages/wrapper/src/Dockerfile
diff --git a/packages/wrapper/src/ascii.js b/packages/wrapper/src/ascii.js
new file mode 100644
index 00000000..a9881a92
--- /dev/null
+++ b/packages/wrapper/src/ascii.js
@@ -0,0 +1 @@
+module.exports = " _ \r\n | | \r\n ___ ___ _ __ ___ | |_ _ _ \r\n \/ __\/ _ \\| \'_ ` _ \\| __| | | |\r\n | (_| (_) | | | | | | |_| |_| |\r\n \\___\\___\/|_| |_| |_|\\__|\\__, |\r\n __\/ |\r\n |___\/ "
\ No newline at end of file
diff --git a/packages/wrapper/src/globals.js b/packages/wrapper/src/globals.js
new file mode 100644
index 00000000..daba5911
--- /dev/null
+++ b/packages/wrapper/src/globals.js
@@ -0,0 +1,22 @@
+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)
\ No newline at end of file
diff --git a/packages/wrapper/src/index.js b/packages/wrapper/src/index.js
index f7f8752a..bdd3386c 100755
--- a/packages/wrapper/src/index.js
+++ b/packages/wrapper/src/index.js
@@ -1,91 +1,331 @@
-require("dotenv").config()
+require("./globals")
-const packagejson = require("../package.json")
+const pm2 = require("pm2")
const fs = require("fs")
const path = require("path")
const express = require("express")
const cors = require("cors")
+const chalk = require("chalk")
+const { exec, spawn, fork } = 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")
-global.remoteRepo = "ragestudio/comty"
-global.cachePath = path.join(process.cwd(), "cache")
-global.distPath = path.join(process.cwd(), "dist")
+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"),
+ },
+]
-function checkDistIntegrity() {
- // check if dist folder exists
- if (!fs.existsSync(global.distPath)) {
- return false
+const ApiServers = [
+ {
+ name: "default",
+ 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}`
}
+]
- // TODO: check the dist checksum with oficial server checksum
-
- return true
-}
-
-function 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
-}
-
-async function runServer() {
- const app = express()
-
- const portFromArgs = process.argv[2]
- let portListen = portFromArgs ? portFromArgs : 9000
-
- app.use(cors({
- origin: "*",
- methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
- preflightContinue: true,
- optionsSuccessStatus: 204
- }))
-
- app.use(express.static(global.distPath))
-
- app.get("/_dist_manifest", async (req, res) => {
- const manifest = fetchDistManifest()
-
- if (!manifest) {
- return res.status(500).send("Dist not found")
+class Main {
+ static checkDistIntegrity() {
+ // check if dist folder exists
+ if (!fs.existsSync(global.distPath)) {
+ return false
}
- return res.json(manifest)
- })
+ // TODO: check the dist checksum with oficial server checksum
- app.get("*", function (req, res) {
- res.sendFile(path.join(global.distPath, "index.html"))
- })
-
- app.listen(portListen)
-
- console.log(`Running Wrapper v${packagejson.version}`)
- console.log(`🌐 Listening app in port [${portListen}]`)
-}
-
-async function main() {
- // check if dist is valid
- if (!checkDistIntegrity()) {
- console.log("DistIntegrity is not valid, downloading latest release...")
- await setupLatestRelease()
+ return true
}
- // start app
- await runServer()
+ 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()
+ }
+ }
+
+ this.initializeWebAppServer()
+ this.initializeAPIProxyServer()
+
+ return this
+ }
+
+ runDevelopmentScript = async () => {
+ const devScript = spawn("npm", ["run", "dev"], {
+ cwd: path.resolve(global.__root, "../../../"),
+ shell: true,
+ stdio: "inherit"
+ })
+
+ // devScript.stdout.on("data", (data) => {
+ // console.log(`${chalk.bgYellow("[WebAPP]")} ${data.toString()}`)
+ // })
+
+ 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(`Closing 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: "eu02.ragestudio.net", //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
+ }
}
-main().catch((err) => {
- console.error(`[FATAL ERROR] >`, err)
-})
\ No newline at end of file
+new Main(process)
\ No newline at end of file
diff --git a/packages/wrapper/src/lib/getInternalIp.js b/packages/wrapper/src/lib/getInternalIp.js
new file mode 100644
index 00000000..f1024394
--- /dev/null
+++ b/packages/wrapper/src/lib/getInternalIp.js
@@ -0,0 +1,12 @@
+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)
+ })
+})
\ No newline at end of file
diff --git a/packages/wrapper/src/lib/useLogger/index.js b/packages/wrapper/src/lib/useLogger/index.js
new file mode 100644
index 00000000..fa33f9b2
--- /dev/null
+++ b/packages/wrapper/src/lib/useLogger/index.js
@@ -0,0 +1,20 @@
+// 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()
+}
\ No newline at end of file