const fs = require('fs') const os = require('os') const path = require('path') const express = require('express') const child_process = require('child_process') const multer = require('multer') const bodyParser = require('body-parser') const chalk = require('chalk') ///////////////////////// Config配置 const HTTP_PORT = 5566 const WORK_DIR = path.dirname(__filename) const SCRIPTS_DIR = path.join(WORK_DIR, "Scripts") ///////////////////////// const app = express() const upload = multer({ dest: os.tmpdir() }) app.use(upload.any()) app.use(bodyParser.urlencoded({ extended: false })) app.use(bodyParser.json()) /// 模版渲染 app.get("/", (req, res) => { let html = fs.readFileSync(path.join(WORK_DIR, "template/guide.html")).toString() let js = fs.readFileSync(path.join(WORK_DIR, "install-runtime.js")).toString() html = html.replace("@@code@@", js) res.send(html) }) app.get('/ping', (req, res) => { console.log('[-] ping..') setTimeout(() => { res.send("pong").end() }, 1000) }) let FILE_DATE = null app.get('/sync', (req, res) => { // console.log('[-] 等待同步到手机..') const { name } = req.query const WIDGET_FILE = path.join(SCRIPTS_DIR, name + '.js') if (!fs.existsSync(WIDGET_FILE)) return res.send("nofile").end() setTimeout(() => { // 判断文件时间 const _time = fs.statSync(WIDGET_FILE).mtimeMs if (_time === FILE_DATE) { res.send("no").end() return // return console.log("[!] 文件没有更改,不同步") } // 同步 res.sendFile(WIDGET_FILE) console.log('[+] 同步到手机完毕') FILE_DATE = _time }, 1000) }) app.post("/sync", (req, res) => { if (req.files.length !== 1) return res.send("no") console.log('[+] Scriptalbe App 已连接') const _file = req.files[0] const FILE_NAME = _file['originalname'] + '.js' const WIDGET_FILE = path.join(SCRIPTS_DIR, FILE_NAME) fs.renameSync(_file['path'], WIDGET_FILE) res.send("ok") console.log(`[*] 小组件源码(${_file['originalname']})已同步,请打开编辑`) FILE_DATE = fs.statSync(WIDGET_FILE).mtimeMs // 尝试打开 let cmd = `code "${WIDGET_FILE}"` if (os.platform() === "win32") { cmd = `cmd.exe /c ${cmd}` } else if (os.platform() === "linux") { let shell = process.env["SHELL"] cmd = `${shell} -c ${cmd}` } else { cmd = `"/Applications/Visual Studio Code.app/Contents/MacOS/Electron" "${WIDGET_FILE}"` } child_process.execSync(cmd) }) // 远程 console,调试中把调试输出内容传送到服务端控制台输出 app.post('/console', (req, res) => { const { t, data } = req.body const _time = new Date().toLocaleString().split(' ')[1] switch (t) { case 'warn': console.warn(`[console.warn / ${_time}]`, typeof data === 'string' ? data : '') if (typeof data === 'object') console.warn(data) break case 'error': console.error(`[console.error / ${_time}]`, typeof data === 'string' ? data : '') if (typeof data === 'object') console.error(data) break default: console.log(`[console.log / ${_time}]`, typeof data === 'string' ? data : '') if (typeof data === 'object') console.log(data) } res.send("ok") }) // 获取PCIP地址 function getIPAdress() { var interfaces = os.networkInterfaces(); for (var devName in interfaces) { var iface = interfaces[devName]; for (var i = 0; i < iface.length; i++) { var alias = iface[i]; if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) { return alias.address; } } } } function main() { const _ip = getIPAdress() const _host = `http://${_ip}:${HTTP_PORT}` console.log(chalk.blue('[*] 「小件件」开发服务运行中')) console.log(chalk.blue(`[-] 地址:${_host}`)) console.log(chalk.blue(`[-] 如果你的手机还没有配置开发环境,请手机 Safari 访问上述地址,查看引导`)) console.log(chalk.blue('[+] 如果你的手机已经安装好环境和小组件模板,请在 Scriptable 里点击小组件模板->远程开发,服务器地址输入:', _ip)) app.listen(HTTP_PORT) } main();