Files
Yae/app.js
2022-04-09 19:33:52 +08:00

177 lines
7.0 KiB
JavaScript

const proxy = require("udp-proxy")
const cp = require("child_process")
const rs = require("./regionServer")
const appcenter = require("./appcenter")
const {
initConfig, splitPacket, upload, decodeProto, log, setupHost, KPacket, debug, checkUpdate,
brotliCompressSync, brotliDecompressSync, checkGameIsRunning, checkPortIsUsing
} = require("./utils")
const { exportData } = require("./export")
const { enablePrivilege, pause } = require("./native")
const onExit = () => {
setupHost(true)
console.log("按任意键退出")
pause()
};
(async () => {
try {
process.on("SIGHUP", () => setupHost(true))
process.on("unhandledRejection", (reason, promise) => {
console.log("Unhandled Rejection at: ", promise, "\n0Reason:", reason)
})
process.on("uncaughtException", (err, origin) => {
appcenter.uploadError(err, true)
console.log(err)
console.log(`Origin: ${origin}`)
process.exit(1)
})
process.on("exit", onExit)
process.on("SIGINT", onExit)
try {
enablePrivilege()
} catch (e) {
console.log("请使用管理员身份运行此程序")
process.exit(-1)
}
appcenter.startup()
let conf = await initConfig()
checkPortIsUsing()
checkGameIsRunning()
log("检查更新")
await checkUpdate()
let gameProcess
let unexpectedExit = true
rs.create(conf,() => {
setupHost()
gameProcess = cp.execFile(conf.executable, { cwd: conf.path },err => {
if (err !== null && !err.killed) {
throw err
}
})
log("启动原神")
gameProcess.on("exit", () => {
if (unexpectedExit) {
console.log("游戏进程异常退出")
process.exit(0)
}
})
},(ip, port, hServer) => {
let login = false
let cache = new Map()
let lastRecvTimestamp = 0
// noinspection JSUnusedGlobalSymbols
const options = {
address: ip,
port: port,
localaddress: "127.0.0.1",
localport: 45678,
middleware: {
message: (msg, sender, next) => {
const buf = Buffer.from(msg)
if (!(login && buf.readUInt8(8) === 0x51)) {
next(msg, sender)
}
},
proxyMsg: (msg, sender, peer, next) => {
try { next(msg, sender, peer) } catch (e) {}
}
}
}
let monitor;
let stopped = false
const createMonitor = () => {
monitor = setInterval(async () => {
if (login && lastRecvTimestamp + 2 < parseInt(Date.now() / 1000) && !stopped) {
stopped = true
unexpectedExit = false
server.close(() => {})
hServer.close()
gameProcess.kill()
clearInterval(monitor)
setupHost(true)
log("正在处理数据,请稍后...")
let packets = Array.from(cache.values())
cache.clear()
packets.sort((a, b) => a.frg - b.frg)
.sort((a, b) => a.sn - b.sn)
.filter(i => i.data.byteLength !== 0)
.forEach(i => {
const psn = i.sn + i.frg
cache.has(psn) ? (() => {
const arr = cache.get(psn)
arr.push(i.data)
cache.set(psn, arr)
})() : cache.set(psn, [i.data])
})
packets = Array.from(cache.values())
.map(arr => {
const data = Buffer.concat(arr)
const len = Buffer.alloc(4)
len.writeUInt32LE(data.length)
return Buffer.concat([len, data])
})
const merged = Buffer.concat(packets)
const compressed = brotliCompressSync(merged)
const response = await upload(compressed)
const data = brotliDecompressSync(response.data)
if (response.status !== 200) {
log(`发生错误: ${data}`)
log(`请求ID: ${response.headers["x-api-requestid"]}`)
log("请联系开发者以获取帮助")
} else {
const proto = await decodeProto(data,"AllAchievement")
await exportData(proto)
}
process.exit(0)
}
},1000)
}
const server = proxy.createServer(options)
server.on("message", (msg, _) => {
if (msg.byteLength > 500) {
login = true
}
})
server.on("error", err => console.log(`Proxy error: ${err.message}` + err.message))
server.on("proxyError", err => console.log(`Proxy error: ${err.message}` + err.message))
server.on("proxyMsg", (msg, _) => {
lastRecvTimestamp = parseInt(Date.now() / 1000)
let buf = Buffer.from(msg)
if (buf.byteLength <= 20) {
switch(buf.readUInt32BE(0)) {
case 325:
createMonitor()
debug("服务端握手应答")
break
case 404:
lastRecvTimestamp = parseInt(Date.now() / 1000) - 2333
break
default:
console.log(`Unhandled: ${buf.toString("hex")}`)
process.exit(2)
break
}
return
}
splitPacket(buf).forEach(sb => {
if (sb.readUInt8(8) === 0x51) {
const p = new KPacket(sb)
if (!cache.has(p.hash)) cache.set(p.hash, p)
}
})
})
return server
}).then(() => log("加载完毕"))
} catch (e) {
console.log(e)
if (e instanceof Error) {
appcenter.uploadError(e, true)
} else {
appcenter.uploadError(Error(e), true)
}
process.exit(1)
}
})()