mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-10 02:54:15 +00:00
Merge branch 'master' of https://github.com/ragestudio/comty
This commit is contained in:
commit
24f6f3c6d6
@ -6,6 +6,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"postinstall": "npm rebuild @tensorflow/tfjs-node --build-from-source && node ./scripts/postinstall.js",
|
"postinstall": "npm rebuild @tensorflow/tfjs-node --build-from-source && node ./scripts/postinstall.js",
|
||||||
"release": "node ./scripts/release.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": "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:file_server": "cd packages/file_server && yarn dev",
|
||||||
"dev:music_server": "cd packages/music_server && yarn dev",
|
"dev:music_server": "cd packages/music_server && yarn dev",
|
||||||
@ -31,4 +32,4 @@
|
|||||||
"pm2": "5.3.0"
|
"pm2": "5.3.0"
|
||||||
},
|
},
|
||||||
"version": "0.49.0"
|
"version": "0.49.0"
|
||||||
}
|
}
|
||||||
|
@ -263,26 +263,37 @@ const OpenTagEditor = ({ tag, onFinish = () => app.navigation.softReload() } = {
|
|||||||
|
|
||||||
const TapShareRender = () => {
|
const TapShareRender = () => {
|
||||||
return <div className="tap-share-render">
|
return <div className="tap-share-render">
|
||||||
|
{
|
||||||
|
!app.cores.nfc.scanning && app.isMobile && <antd.Alert
|
||||||
|
type="warning"
|
||||||
|
message="NFC is disabled"
|
||||||
|
description="You can enable it in your device settings."
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
<div className="tap-share-field">
|
<div className="tap-share-field">
|
||||||
<div className="tap-share-field_header">
|
<div className="tap-share-field_header">
|
||||||
<h1>
|
<h1>
|
||||||
<Icons.MdSpoke /> Registered Tags
|
<Icons.MdSpoke /> Registered Tags
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<span className="tip">
|
{
|
||||||
<Icons.MdInfo /> You can quickly edit your tags by tapping them.
|
app.cores.nfc.scanning && <span className="tip">
|
||||||
</span>
|
<Icons.MdInfo /> You can quickly edit your tags by tapping them.
|
||||||
|
</span>
|
||||||
|
}
|
||||||
<OwnTags />
|
<OwnTags />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<antd.Button
|
{
|
||||||
type="primary"
|
app.isMobile && <antd.Button
|
||||||
icon={<Icons.Plus />}
|
type="primary"
|
||||||
onClick={() => OpenTagEditor()}
|
icon={<Icons.Plus />}
|
||||||
>
|
onClick={() => OpenTagEditor()}
|
||||||
Add new
|
>
|
||||||
</antd.Button>
|
Add new
|
||||||
|
</antd.Button>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,13 +22,6 @@ export default (props) => {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const nfcInstance = app.cores.nfc.instance()
|
|
||||||
|
|
||||||
if (!nfcInstance) {
|
|
||||||
setError(NFC_ERRORS.NFC_NOT_AVAILABLE)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
setError(null)
|
setError(null)
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
|
||||||
@ -40,7 +33,7 @@ export default (props) => {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
nfcInstance.write({
|
app.cores.nfc.writeNdef({
|
||||||
records: [{
|
records: [{
|
||||||
recordType: "url",
|
recordType: "url",
|
||||||
data: context.values.endpoint_url
|
data: context.values.endpoint_url
|
||||||
|
@ -66,7 +66,6 @@ import loadable from "@loadable/component"
|
|||||||
|
|
||||||
import { StatusBar, Style } from "@capacitor/status-bar"
|
import { StatusBar, Style } from "@capacitor/status-bar"
|
||||||
import { App as CapacitorApp } from "@capacitor/app"
|
import { App as CapacitorApp } from "@capacitor/app"
|
||||||
import { SplashScreen } from "@capacitor/splash-screen"
|
|
||||||
import { CapacitorUpdater } from "@capgo/capacitor-updater"
|
import { CapacitorUpdater } from "@capgo/capacitor-updater"
|
||||||
|
|
||||||
import SessionModel from "models/session"
|
import SessionModel from "models/session"
|
||||||
@ -98,6 +97,8 @@ import * as Router from "./router"
|
|||||||
|
|
||||||
import "theme/index.less"
|
import "theme/index.less"
|
||||||
|
|
||||||
|
console.log(`REACT VERSION: ${React.version}`)
|
||||||
|
|
||||||
CapacitorUpdater.notifyAppReady()
|
CapacitorUpdater.notifyAppReady()
|
||||||
|
|
||||||
class ComtyApp extends React.Component {
|
class ComtyApp extends React.Component {
|
||||||
@ -118,15 +119,10 @@ class ComtyApp extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static splashAwaitEvent = "app.initialization.finish"
|
static splashAwaitEvent = "app.initialization.finish"
|
||||||
|
|
||||||
static async initialize() {
|
static async initialize() {
|
||||||
SplashScreen.show({
|
|
||||||
autoHide: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
window.app.splash = SplashScreen
|
|
||||||
window.app.version = config.package.version
|
window.app.version = config.package.version
|
||||||
window.app.message = antd.message
|
window.app.message = antd.message
|
||||||
|
window.app.isCapacitor = window.navigator.userAgent === "capacitor"
|
||||||
|
|
||||||
window.localStorage.setItem("last_version", window.app.version)
|
window.localStorage.setItem("last_version", window.app.version)
|
||||||
|
|
||||||
@ -492,8 +488,6 @@ class ComtyApp extends React.Component {
|
|||||||
this.setState({ initialized: true })
|
this.setState({ initialized: true })
|
||||||
|
|
||||||
Utils.handleOpenDevTools()
|
Utils.handleOpenDevTools()
|
||||||
|
|
||||||
SplashScreen.hide()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRuntimeStateUpdate = (state) => {
|
onRuntimeStateUpdate = (state) => {
|
||||||
|
@ -2,8 +2,6 @@ import React from "react"
|
|||||||
import classnames from "classnames"
|
import classnames from "classnames"
|
||||||
import * as antd from "antd"
|
import * as antd from "antd"
|
||||||
|
|
||||||
import { createIconRender } from "components/Icons"
|
|
||||||
|
|
||||||
import "./index.less"
|
import "./index.less"
|
||||||
|
|
||||||
const NavMenu = (props) => {
|
const NavMenu = (props) => {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import Core from "evite/src/core"
|
import Core from "evite/src/core"
|
||||||
|
import { Haptics } from "@capacitor/haptics"
|
||||||
|
|
||||||
const vibrationPatterns = {
|
const vibrationPatterns = {
|
||||||
light: [10],
|
light: [10],
|
||||||
@ -19,6 +20,10 @@ export default class HapticsCore extends Core {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async onInitialize() {
|
async onInitialize() {
|
||||||
|
if (window.navigator.userAgent === "capacitor") {
|
||||||
|
navigator.vibrate = this.nativeVibrate
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener("click", this.handleClickEvent)
|
document.addEventListener("click", this.handleClickEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,6 +32,18 @@ export default class HapticsCore extends Core {
|
|||||||
vibrate: this.vibrate.bind(this),
|
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) => {
|
handleClickEvent = (event) => {
|
||||||
const button = event.target.closest("button") || event.target.closest(".ant-btn")
|
const button = event.target.closest("button") || event.target.closest(".ant-btn")
|
||||||
|
|
||||||
|
@ -1,40 +1,137 @@
|
|||||||
import Core from "evite/src/core"
|
import Core from "evite/src/core"
|
||||||
import TapShareDialog from "components/TapShare/Dialog"
|
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 {
|
export default class NFC extends Core {
|
||||||
static refName = "NFC"
|
static refName = "NFC"
|
||||||
|
|
||||||
static namespace = "nfc"
|
static namespace = "nfc"
|
||||||
|
|
||||||
|
isNativeMode = false
|
||||||
|
|
||||||
instance = null
|
instance = null
|
||||||
|
|
||||||
subscribers = []
|
subscribers = []
|
||||||
|
|
||||||
public = {
|
public = {
|
||||||
incompatible: null,
|
incompatible: true,
|
||||||
scanning: false,
|
scanning: false,
|
||||||
startScanning: this.startScanning.bind(this),
|
writeNdef: this.writeNdef.bind(this),
|
||||||
instance: function () { return this.instance }.bind(this),
|
instance: function () { return this.instance }.bind(this),
|
||||||
subscribe: this.subscribe.bind(this),
|
subscribe: this.subscribe.bind(this),
|
||||||
unsubscribe: this.unsubscribe.bind(this),
|
unsubscribe: this.unsubscribe.bind(this),
|
||||||
}
|
}
|
||||||
|
|
||||||
async onInitialize() {
|
subscribe(callback) {
|
||||||
if ("NDEFReader" in window === false) {
|
// check if scan service is available, if not try to initialize
|
||||||
return this.public.incompatible = true
|
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() {
|
async startScanning() {
|
||||||
try {
|
try {
|
||||||
//await navigator.permissions.query({ name: "nfc" })
|
await this.instance.scan()
|
||||||
|
|
||||||
this.instance.scan()
|
|
||||||
|
|
||||||
this.public.scanning = true
|
this.public.scanning = true
|
||||||
this.public.incompatible = false
|
this.public.incompatible = false
|
||||||
@ -48,23 +145,11 @@ export default class NFC extends Core {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe(callback) {
|
startNativeScanning() {
|
||||||
// check if scan service is available, if not try to initialize
|
this.public.scanning = true
|
||||||
if (this.public.scanning === false) {
|
this.public.incompatible = false
|
||||||
this.startScanning()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.subscribers.push(callback)
|
return this.registerNativeEventListeners()
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleRead(tag) {
|
handleRead(tag) {
|
||||||
@ -75,8 +160,6 @@ export default class NFC extends Core {
|
|||||||
subscriber(null, tag)
|
subscriber(null, tag)
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(this.subscribers)
|
|
||||||
|
|
||||||
if (this.subscribers.length === 0) {
|
if (this.subscribers.length === 0) {
|
||||||
if (tag.message.records?.length > 0) {
|
if (tag.message.records?.length > 0) {
|
||||||
// open dialog
|
// 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) {
|
handleError(error) {
|
||||||
this.subscribers.forEach((subscriber) => {
|
this.subscribers.forEach((subscriber) => {
|
||||||
subscriber(error, null)
|
subscriber(error, null)
|
||||||
@ -99,4 +208,57 @@ export default class NFC extends Core {
|
|||||||
this.instance.addEventListener("reading", this.handleRead.bind(this))
|
this.instance.addEventListener("reading", this.handleRead.bind(this))
|
||||||
this.instance.addEventListener("error", this.handleError.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)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,4 +1,10 @@
|
|||||||
function composeRemote(path) {
|
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]
|
return envOrigins[process.env.NODE_ENV ?? "production"][path]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,6 +25,14 @@ const envOrigins = {
|
|||||||
music: `http://${getCurrentHostname()}:3050`,
|
music: `http://${getCurrentHostname()}:3050`,
|
||||||
files: `http://${getCurrentHostname()}:3060`,
|
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": {
|
"production": {
|
||||||
default: "https://api.comty.app",
|
default: "https://api.comty.app",
|
||||||
chat: `https://chat_api.comty.app`,
|
chat: `https://chat_api.comty.app`,
|
||||||
|
@ -9,12 +9,16 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"7zip-min": "^1.4.3",
|
"7zip-min": "^1.4.3",
|
||||||
"@octokit/rest": "^19.0.4",
|
"@octokit/rest": "^19.0.4",
|
||||||
"cors": "2.8.5",
|
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
|
"chalk": "4.1.2",
|
||||||
|
"cors": "2.8.5",
|
||||||
"dotenv": "^16.0.3",
|
"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": {
|
"devDependencies": {
|
||||||
"corenode": "^0.28.26"
|
"corenode": "^0.28.26"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
packages/wrapper/src/ascii.js
Normal file
1
packages/wrapper/src/ascii.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = " _ \r\n | | \r\n ___ ___ _ __ ___ | |_ _ _ \r\n \/ __\/ _ \\| \'_ ` _ \\| __| | | |\r\n | (_| (_) | | | | | | |_| |_| |\r\n \\___\\___\/|_| |_| |_|\\__|\\__, |\r\n __\/ |\r\n |___\/ "
|
22
packages/wrapper/src/globals.js
Normal file
22
packages/wrapper/src/globals.js
Normal file
@ -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)
|
@ -1,91 +1,331 @@
|
|||||||
require("dotenv").config()
|
require("./globals")
|
||||||
|
|
||||||
const packagejson = require("../package.json")
|
const pm2 = require("pm2")
|
||||||
|
|
||||||
const fs = require("fs")
|
const fs = require("fs")
|
||||||
const path = require("path")
|
const path = require("path")
|
||||||
const express = require("express")
|
const express = require("express")
|
||||||
const cors = require("cors")
|
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")
|
const { setupLatestRelease } = require("./lib/setupDist")
|
||||||
|
|
||||||
global.remoteRepo = "ragestudio/comty"
|
const developmentServers = [
|
||||||
global.cachePath = path.join(process.cwd(), "cache")
|
{
|
||||||
global.distPath = path.join(process.cwd(), "dist")
|
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() {
|
const ApiServers = [
|
||||||
// check if dist folder exists
|
{
|
||||||
if (!fs.existsSync(global.distPath)) {
|
name: "default",
|
||||||
return false
|
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
|
class Main {
|
||||||
|
static checkDistIntegrity() {
|
||||||
return true
|
// check if dist folder exists
|
||||||
}
|
if (!fs.existsSync(global.distPath)) {
|
||||||
|
return false
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.json(manifest)
|
// TODO: check the dist checksum with oficial server checksum
|
||||||
})
|
|
||||||
|
|
||||||
app.get("*", function (req, res) {
|
return true
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// start app
|
static fetchDistManifest() {
|
||||||
await runServer()
|
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) => {
|
new Main(process)
|
||||||
console.error(`[FATAL ERROR] >`, err)
|
|
||||||
})
|
|
12
packages/wrapper/src/lib/getInternalIp.js
Normal file
12
packages/wrapper/src/lib/getInternalIp.js
Normal file
@ -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)
|
||||||
|
})
|
||||||
|
})
|
20
packages/wrapper/src/lib/useLogger/index.js
Normal file
20
packages/wrapper/src/lib/useLogger/index.js
Normal file
@ -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()
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user