Updated to latest service-core, fixed some bugs and made it runnable

This commit is contained in:
Jonatan Nilsson 2022-03-28 07:27:18 +00:00
parent 7e127cd58f
commit f64acc95eb
10 changed files with 226 additions and 150 deletions

View file

@ -1,3 +1,4 @@
import defaults from '../defaults.mjs'
import { formatLog } from './loghelper.mjs' import { formatLog } from './loghelper.mjs'
/* /*
@ -6,7 +7,16 @@ import { formatLog } from './loghelper.mjs'
* Get config * Get config
*/ */
export async function config(ctx, data, cb) { export async function config(ctx, data, cb) {
cb(ctx.config) let merge = {
applications: []
}
for (let app of ctx.core.applications) {
merge[app.name] = app.config
merge.applications.push(app.name)
}
let out = defaults(ctx.db.config, merge)
console.log(out)
cb(out)
} }
/* /*
@ -94,8 +104,8 @@ export async function updatestart(ctx, data, cb) {
*/ */
export async function listencore(ctx) { export async function listencore(ctx) {
ctx.socket.join('core') ctx.socket.join('core')
ctx.socket.emit('core.db', ctx.db.get('core').value()) ctx.socket.emit('core.db', ctx.db.data.core)
ctx.socket.emit('core.status', ctx.core.status()) ctx.socket.emit('core.status', {})
} }
/* /*

View file

@ -1,4 +1,4 @@
import _ from 'lodash' import defaults from '../defaults.mjs'
import { format } from 'util' import { format } from 'util'
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
@ -64,7 +64,7 @@ function indent(s) {
} }
export function formatLog(data) { export function formatLog(data) {
let rec = _.cloneDeep(data) let rec = defaults(data)
delete rec.v; delete rec.v;

34
api/defaults.mjs Normal file
View file

@ -0,0 +1,34 @@
// taken from isobject npm library
function isObject(val) {
return val != null && typeof val === 'object' && Array.isArray(val) === false
}
export default function defaults(options, def) {
let out = { }
if (options) {
Object.keys(options || {}).forEach(key => {
out[key] = options[key]
if (Array.isArray(out[key])) {
out[key] = out[key].map(item => {
if (isObject(item)) return defaults(item)
return item
})
} else if (out[key] && typeof out[key] === 'object') {
out[key] = defaults(options[key], def && def[key])
}
})
}
if (def) {
Object.keys(def).forEach(function(key) {
if (typeof out[key] === 'undefined') {
out[key] = def[key]
}
})
}
return out
}

View file

@ -21,32 +21,31 @@ function register(ctx, name, method) {
} }
function onConnection(server, config, db, log, coreService, data) { function onConnection(server, ctx, data) {
const io = server const io = server
const socket = data const socket = data
const child = log.child({ const child = ctx.log.child({
id: socket.id, id: socket.id,
}) })
child.event = log.event child.event = ctx.log.event
child.info('Got new socket connection') child.info('Got new socket connection')
let ctx = { let ioCtx = {
config, io: io,
io, socket: socket,
socket,
log: child, log: child,
db, db: ctx.db,
core: coreService, core: ctx.core,
logroot: log, logroot: ctx.log,
} }
ctx.socket.on('disconnect', function() { ioCtx.socket.on('disconnect', function() {
child.info('Closed connection') child.info('Closed connection')
}) })
register(ctx, 'core', core) register(ioCtx, 'core', core)
} }
export default onConnection export default onConnection

View file

@ -1,84 +1,75 @@
import path from 'path'
import { fileURLToPath } from 'url'
import socket from 'socket.io-serveronly' import socket from 'socket.io-serveronly'
import nStatic from 'node-static' import nStatic from 'node-static'
import coremonitor from './core/coremonitor.mjs' // import coremonitor from './core/coremonitor.mjs'
import onConnection from './routerio.mjs' import onConnection from './routerio.mjs'
export function run(config, db, log, core, http, port) { export function run(http, port, ctx) {
return new Promise(function(resolve, reject) { let localUtil = new ctx.sc.Util(import.meta.url)
core.startMonitor()
const __dirname = path.dirname(fileURLToPath(import.meta.url)) const staticRoot = localUtil.getPathFromRoot('../public')
const staticRoot = path.join(__dirname,'../public')
const fileServer = new nStatic.Server(staticRoot) const fileServer = new nStatic.Server(staticRoot)
const server = http.createServer(function (req, res) { const server = http.createServer(function (req, res) {
const child = log.child({}) const child = ctx.log.child({})
const d1 = new Date().getTime() const d1 = new Date().getTime()
let finishedRequest = false let finishedRequest = false
var done = function () { var done = function () {
if (finishedRequest) return if (finishedRequest) return
finishedRequest = true finishedRequest = true
if (req.url === '/main.css.map') return if (req.url === '/main.css.map') return
var requestTime = new Date().getTime() - d1 var requestTime = new Date().getTime() - d1
let level = 'debug' let level = 'debug'
if (res.statusCode >= 400) { if (res.statusCode >= 400) {
level = 'warn' level = 'warn'
} }
if (res.statusCode >= 500) { if (res.statusCode >= 500) {
level = 'error' level = 'error'
}
let status = ''
if (res.statusCode >= 400) {
status = res.statusCode + ' '
}
child[level]({
duration: requestTime,
status: res.statusCode,
}, `<-- ${status}${req.method} ${req.url}`)
} }
res.addListener('finish', done); let status = ''
res.addListener('close', done); if (res.statusCode >= 400) {
status = res.statusCode + ' '
}
req.addListener('end', function () { child[level]({
if (req.url === '/') { duration: requestTime,
res.writeHead(302, { Location: '/index.html' }) status: res.statusCode,
return res.end() }, `<-- ${status}${req.method} ${req.url}`)
} }
fileServer.serve(req, res, function (err) { res.addListener('finish', done);
if (err) { res.addListener('close', done);
if (err.status !== 404) {
log.error(err, req.url);
}
res.writeHead(err.status, err.headers); req.addListener('end', function () {
res.end(err.message); if (req.url === '/') {
res.writeHead(302, { Location: '/index.html' })
return res.end()
}
fileServer.serve(req, res, function (err) {
if (err) {
if (err.status !== 404) {
ctx.log.error(err, req.url);
} }
});
}).resume()
})
const io = new socket(server) res.writeHead(err.status, err.headers);
io.on('connection', onConnection.bind(this, io, config, db, log, core)) res.end(err.message);
}
coremonitor(io, config, db, log, core) });
}).resume()
server.listen(port, '0.0.0.0', function(err) {
if (err) {
return reject(err)
}
log.event.info(`Server is listening on ${port} serving files on ${staticRoot}`)
log.info(`Server is listening on ${port} serving files on ${staticRoot}`)
resolve()
})
}) })
const io = new socket(server)
io.on('connection', onConnection.bind(this, io, ctx))
// coremonitor(io, config, db, log, core)
return server.listenAsync(port)
.then(function() {
ctx.log.info('Server is listening on port ' + port)
})
} }

View file

@ -5,61 +5,43 @@ const Module = require('../module')
const Status = Module({ const Status = Module({
init: function() { init: function() {
this._name = '...loading...' this._name = '...loading...'
this._management = { this._apps = []
name: 'manage',
port: null,
repository: null,
active: null,
latestInstalled: null,
latestVersion: null,
running: null,
updating: null,
starting: null,
}
this._app = {
name: 'app',
port: null,
repository: null,
active: null,
latestInstalled: null,
latestVersion: null,
running: null,
updating: null,
starting: null,
}
this._socketOn(() => this.loadData()) this._socketOn(() => this.loadData())
}, },
loadData: function() { loadData: function() {
socket.emit('core.config', {}, (res) => { socket.emit('core.config', {}, (res) => {
this._name = res.name + ' - ' + res.serviceName this._apps = []
this._app.port = res.port console.log('config', res)
this._app.repository = res.appRepository this._name = res.name
this._management.port = res.managePort if (res.title) {
this._management.repository = res.manageRepository this._name += ' - ' + res.title
}
for (let appName of res.applications) {
this._apps.push({
name: appName,
config: res[appName],
})
}
console.log(this._apps)
m.redraw() m.redraw()
}) })
this.on('core.db', (res) => { this.on('core.db', (res) => {
this._management.active = res.manageActive console.log('db', res)
this._management.latestInstalled = res.manageLatestInstalled
this._management.latestVersion = res.manageLatestVersion
this._app.active = res.appActive
this._app.latestInstalled = res.appLatestInstalled
this._app.latestVersion = res.appLatestVersion
m.redraw() m.redraw()
}) })
this.on('core.status', (res) => { this.on('core.status', (res) => {
console.log(res) console.log(res)
this._management.running = res.manage /*this._management.running = res.manage
this._management.updating = res.manageUpdating this._management.updating = res.manageUpdating
this._management.starting = res.manageStarting this._management.starting = res.manageStarting
this._app.running = res.app this._app.running = res.app
this._app.updating = res.appUpdating this._app.updating = res.appUpdating
this._app.starting = res.appStarting this._app.starting = res.appStarting*/
m.redraw() m.redraw()
}) })
@ -97,36 +79,36 @@ const Status = Module({
return m('div#status', [ return m('div#status', [
m('h1.header', this._name), m('h1.header', this._name),
m('div.split', [ m('div.split', [
loopOver.map((group) => { this._apps.map((app) => {
return m('div.item', [ return m('div.item', [
m('h4', group[0]), m('h4', app.name),
m('p', this[group[1]].port m('p', app.config.port
? `Port: ${this[group[1]].port}` ? `Port: ${app.config.port}`
: ''), : ''),
m('p', this[group[1]].repository m('p', app.config.repository
? `${this[group[1]].repository}` ? `${app.config.repository}`
: '< no repository >'), : '< no repository >'),
m('p', this[group[1]].active m('p', app.config.active
? `Running version: ${this[group[1]].active}` ? `Running version: ${app.config.active}`
: '< no running version >'), : '< no running version >'),
m('p', this[group[1]].latestInstalled m('p', app.config.latestInstalled
? `Latest installed: ${this[group[1]].latestInstalled}` ? `Latest installed: ${app.config.latestInstalled}`
: '< no version installed >'), : '< no version installed >'),
m('p', this[group[1]].latestVersion m('p', app.config.latestVersion
? `Latest version: ${this[group[1]].latestVersion}` ? `Latest version: ${app.config.latestVersion}`
: '< no version found >'), : '< no version found >'),
this[group[1]].running !== null && this[group[1]].repository app.config.running !== null && app.config.repository
? m('p', ? m('p',
{ class: this[group[1]].running ? 'running' : 'notrunning' }, { class: app.config.running ? 'running' : 'notrunning' },
this[group[1]].running ? 'Running' : 'Not Running' app.config.running ? 'Running' : 'Not Running'
) )
: null, : null,
!this[group[1]].running && (this[group[1]].updating || this[group[1]].starting) !app.config.running && (app.config.updating || app.config.starting)
? m('div.status', this.getStatus(this[group[1]])) ? m('div.status', this.getStatus(app.config))
: null, : null,
m('button', { m('button', {
hidden: this[group[1]].running || this[group[1]].updating || this[group[1]].starting || !this[group[1]].repository, hidden: app.config.running || app.config.updating || app.config.starting || !app.config.repository,
onclick: () => this.start(this[group[1]].name), onclick: () => this.start(app.config.name),
}, 'Update/Start') }, 'Update/Start')
]) ])
}), }),

42
dev.mjs Normal file
View file

@ -0,0 +1,42 @@
import { ServiceCore, Application, getLog, Util, Core } from 'service-core'
import * as index from './index.mjs'
let util = new Util(import.meta.url)
const helloWorldConfig = {
"provider": "git",
"url": "https://git.nfp.is/api/v1/repos/thething/sc-helloworld/releases",
"port": 8888,
}
var core = new ServiceCore('sc-manager', import.meta.url)
core.config['hello-world'] = helloWorldConfig
core.setConfig({
port: 4271,
})
core.init(index).then(function() {
let provConstructor = Core.providers.get(core.db.config['hello-world'].provider)
let provider = new provConstructor(core.db.config['hello-world'])
let helloWorld = new Application({
db: core.db,
util: util,
log: getLog('hello-world'),
core: core.core,
}, provider, 'hello-world')
core.core.applications.push(helloWorld)
core.core.applicationMap.set('hello-world', helloWorld)
helloWorld.startAutoupdater()
return core.run()
}).then(function() {
return core.core.applicationMap.get('hello-world').update()
}).then(function() {
return core.core.runApplication(core.core.applicationMap.get('hello-world'))
}).then(function() {
let helloApp = core.core.applicationMap.get('hello-world')
helloApp.on('updated', core.core.runApplication.bind(core.core, helloApp))
})

0
hello-world/.gitkeep Normal file
View file

View file

@ -1,5 +1,5 @@
export function start(config, db, log, core, http, port) { import { run } from "./api/server.mjs"
return import('./api/server.mjs').then(function(module) {
return module.run(config, db, log, core, http, port) export function start(http, port, ctx) {
}) return run(http, port, ctx)
} }

View file

@ -4,24 +4,42 @@
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"js:build:main": "asbundle client/index.js public/main.js", "build:main": "asbundle client/index.js public/main.js",
"dev:server": "nodemon --watch runner.mjs --watch api runner.mjs | bunyan", "build:main:watch": "npm-watch build:main",
"dev:client": "nodemon --watch client --exec \"npm run js:build:main\"", "dev:server": "node dev.mjs | bunyan",
"build": "npm run js:build:main", "dev:server:watch": "npm-watch dev:server",
"dev": "npm run dev:server && npm run dev:client",
"build": "npm run build:main",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"watch": {
"dev:server": {
"patterns": [
"api/*"
],
"extensions": "js,mjs",
"quiet": true,
"inherit": true
},
"build:main": {
"patterns": [
"client/*"
],
"extensions": "js,mjs",
"quiet": true,
"inherit": true
}
},
"author": "", "author": "",
"license": "WTFPL", "license": "WTFPL",
"dependencies": { "dependencies": {
"lodash": "^4.17.20", "flaska": "^1.2.1",
"node-static": "^0.7.11", "node-static": "^0.7.11",
"socket.io-serveronly": "^2.3.0" "socket.io-serveronly": "^2.3.0"
}, },
"devDependencies": { "devDependencies": {
"asbundle": "^2.6.1", "asbundle": "^2.6.1",
"bunyan-lite": "^1.0.1",
"mithril": "^2.0.4", "mithril": "^2.0.4",
"nodemon": "^2.0.4", "service-core": "^3.0.0-beta.11"
"service-core": "^2.0.0"
} }
} }