-
Notifications
You must be signed in to change notification settings - Fork 0
/
rconf.js
executable file
·125 lines (97 loc) · 4.12 KB
/
rconf.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/env node-dev
const decode = JSON.parse
const encode = JSON.stringify
for (const f in require('ramda'))
global[f] = require('ramda')[f]
global.conf = null
const {pp, getDiff, every, detectLanguage, joinPath, run, calculateHash, coerceArray, fs, os, getIPV4Interfaces} = require('./helpers')
const {updateConfig, hasConfig} = require('./config')
global.platform = [os.hostname(), os.arch(), os.platform(), os.release(), os.version()].join('-').replace(/#/gim,'')
// console.log(`platform:\n ${platform}\n`)
if (process.argv[2]) return require('./client')(process.argv[2])
const express = require('express')
const app = express()
require('./ws').initWSServer(app)
const LOGFILE = joinPath(DATADIR, '.log', (new Date).toISOString().slice(0, 10)+'.json')
const log = (message, ws, broadcastNode = false) => {
if (ws?._socket?.remoteAddress) message.ip = ws._socket.remoteAddress.replace(/.*:(.*)/, '$1')
if (ws && !message.id) message.id=message.ip
message.time = new Date()
if (message?.json?.status) {
message.status = message.json.status
delete message.json.status
}
fs.promises.appendFile(LOGFILE, JSON.stringify(message)+'\r\n')
console.log(JSON.stringify(message, null, ' '))
Server.broadcast('log', message)
if (broadcastNode) Server.broadcast('node', message)
}
log({message: 'restarted', status: 'ok'})
for (const p of ['uncaughtException', 'unhandledRejection', 'warning']) {
process.on(p, (error) => log({id: 'rconf', message: error.message, status: 'error'}))
}
Server.on('connect', ws => Sync.broadcast('config:ask', {}))
Sync.on('connect', ws => {
ws._emit('tags', uniq(flatten(values(pluck('tag', conf.services)))))
})
Sync.on('disconnect', ws => log({status: 'error', message: 'disconnected'}, ws, true))
Server.on('file:delete', (ws, {file}) => {
fs.unlink(joinPath(DATADIR, file), x => {})
})
Server.on('file:rename', (ws, {file, to}) => {
fs.rename(joinPath(DATADIR, file), joinPath(DATADIR, to), x => {})
})
Server.on('file:delete', (ws, {file}) => {
fs.unlink(joinPath(DATADIR, file), x => {})
})
Server.on('file:save', (ws, {file, value}) => {
fs.writeFileSync(joinPath(DATADIR, file), value)
updateConfig()
Sync.broadcast('config:ask', {})
return {'status': 'saved'}
})
Server.on('file:list', ws =>
sortBy(x => x.name == 'rconf.yaml' ? 'A' : x.name[0], map(name => ({name, metadata: {
language: detectLanguage(name),
value: fs.readFileSync(joinPath(DATADIR, name), 'utf8')
}}), reject(x => x == '.log', fs.readdirSync(DATADIR))))
)
Server.on('log:today', (ws, message) =>
reject(isEmpty, fs.readFileSync(LOGFILE, 'utf8').split(/$\n/gim)).map(x => JSON.parse(x.replace(/$\n/gim, '')))
)
Sync.on('log', (ws, message) => log(message, ws, false))
Sync.on('config', (ws, {id, token, tags, platform, hash}) => {
const ip = ws._socket.remoteAddress.replace(/.*:(.*)/, '$1')
const message = {platform, tags, id: id || ip, ip, status: 'ok', time: new Date(), message: 'connected'}
if (conf.token != token) {
message.message = 'unathorized'
message.status = 'error'
Server.broadcast('node', message)
return Server.broadcast('log', message)
}
const hasTag = tag => intersection(tags, tag).length
const c = clone(conf.services)
mapObjIndexed(({tag, platform}, service) => {
if (!new RegExp(join('|', platform), 'gim').test(platform) || !hasTag(tag)) delete c[service]
}, c)
message.config = c
Server.broadcast('node', message)
if (calculateHash(c) == hash) return
return c
})
const launchServer = () => {
if (conf?.auth) {
const basicAuth = require('express-basic-auth')
app.use([
basicAuth({ users: conf.auth, challenge: true, }),
express.static(joinPath(__dirname, 'public'))
])
}
console.log('To install on remote machine:\n curl https://i.jpillora.com/slavaGanzin/rconf! | bash\n')
values(getIPV4Interfaces('^'+conf.networks.join('$|^')+'$')).map(interface =>
app.listen(14141, interface.address, () => {
console.log(`${interface.name}:\n Web UI:\n http://${interface.address}:14141 \n sync config command:\n rconf http://${interface.address}:14141/${conf.token}\n`)
})
)
}
hasConfig().then(launchServer)