Skip to content

Commit 6c74d02

Browse files
committed
Convert server to JS
1 parent 4b2b256 commit 6c74d02

1 file changed

Lines changed: 217 additions & 181 deletions

File tree

server/server.js

Lines changed: 217 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -1,181 +1,217 @@
1-
# plugmatic plugin, server-side component
2-
# These handlers are launched with the wiki server.
3-
4-
fs = require 'fs'
5-
glob = require 'glob'
6-
async = require 'async'
7-
jsonfile = require 'jsonfile'
8-
https = require 'https'
9-
execFile = require('child_process').execFile
10-
11-
12-
github = (path, done) ->
13-
options =
14-
host: 'raw.githubusercontent.com'
15-
port: 443
16-
method: 'GET'
17-
path: path
18-
try
19-
req = https.get options, (res) ->
20-
res.setEncoding 'utf8'
21-
data = ''
22-
res.on 'error', () ->
23-
done null
24-
res.on 'timeout', () ->
25-
done null
26-
res.on 'data', (d) ->
27-
data += d
28-
res.on 'end', () ->
29-
done data
30-
req.on 'error', () ->
31-
done null
32-
catch e
33-
done null
34-
35-
# http://www.sebastianseilund.com/nodejs-async-in-practice
36-
37-
startServer = (params) ->
38-
app = params.app
39-
argv = params.argv
40-
bundle = null
41-
42-
github '/fedwiki/wiki/master/package.json', (data) ->
43-
bundle =
44-
date: Date.now()
45-
data: JSON.parse data||'{"dependencies":{}}'
46-
47-
route = (endpoint) -> "/plugin/plugmatic/#{endpoint}"
48-
path = (file) -> "#{argv.packageDir}/#{file}"
49-
50-
51-
info = (file, done) ->
52-
plugin = file.slice 12
53-
site = {plugin}
54-
55-
birth = (cb) ->
56-
fs.stat path("#{file}/client/#{plugin}.js"), (err, stat) ->
57-
site.birth = stat?.birthtime?.getTime(); cb()
58-
pages = (cb) ->
59-
synopsis = (slug, cb2) ->
60-
jsonfile.readFile path("#{file}/pages/#{slug}"), {throws:false}, (err, page) ->
61-
title = page.title || slug
62-
synopsis = page.story?[0]?.text || page.story?[1]?.text || 'empty'
63-
cb2 null, {file, slug, title, synopsis}
64-
fs.readdir path("#{file}/pages"), (err, slugs) ->
65-
async.map slugs||[], synopsis, (err, pages) ->
66-
site.pages = pages; cb()
67-
packagejson = (cb) ->
68-
jsonfile.readFile path("#{file}/package.json"), {throws:false}, (err, packagejson) ->
69-
site.package = packagejson; cb()
70-
factory = (cb) ->
71-
jsonfile.readFile path("#{file}/factory.json"), {throws:false}, (err, factory) ->
72-
site.factory = factory; cb()
73-
authors = (cb) ->
74-
fs.readFile path("#{file}/AUTHORS.txt"), 'utf-8', (err, authors) ->
75-
site.authors = authors; cb()
76-
# persona = (cb) ->
77-
# fs.readFile path("#{file}/status/persona.identity"),'utf8', (err, identity) ->
78-
# site.persona = identity; cb()
79-
# openid = (cb) ->
80-
# fs.readFile path("#{file}/status/open_id.identity"),'utf8', (err, identity) ->
81-
# site.openid = identity; cb()
82-
async.series [birth,authors,packagejson,factory,pages], (err) ->
83-
done null, site
84-
85-
plugmap = (done) ->
86-
glob "wiki-plugin-*", {cwd: argv.packageDir}, (err, files) ->
87-
return done(err,null) if err
88-
async.map files||[], info, (err, install) ->
89-
return done(err,null) if err
90-
done(null, install)
91-
92-
93-
view = (plugin, done) ->
94-
if /^\w+$/.test(plugin)
95-
pkg = "wiki-plugin-#{plugin}"
96-
execFile 'npm', ['view', "#{pkg}", '--json'], (err, stdout, stderr) ->
97-
try npm = JSON.parse stdout
98-
done null, {plugin, pkg, npm}
99-
100-
farm = (req, res, next) ->
101-
if argv.f
102-
next()
103-
else
104-
res.status(404).send {error: 'service requires farm mode'}
105-
106-
admin = (req, res, next) ->
107-
if app.securityhandler.isAdmin(req)
108-
next()
109-
else
110-
admin = "none specified" unless argv.admin
111-
user = "not logged in" unless req.session?.passport?.user || req.session?.email || req.session?.friend
112-
res.status(403).send {error: 'service requires admin user', admin, user}
113-
114-
app.get route('page/:slug.json'), (req, res) ->
115-
plugmap (err, install) ->
116-
for i in install
117-
for p in i.pages
118-
if p.slug is req.params.slug
119-
return jsonfile.readFile path("#{p.file}/pages/#{p.slug}"), {throws:false}, (err, page) ->
120-
res.json page
121-
res.sendStatus 404
122-
123-
app.get route('file/:file/slug/:slug'), (req, res) ->
124-
jsonfile.readFile path("#{req.params.file}/pages/#{req.params.slug}"), {throws:false}, (err, page) ->
125-
if err
126-
res.sendStatus 404
127-
else
128-
res.json page
129-
130-
app.get route('sitemap.json'), (req, res) ->
131-
plugmap (err, install) ->
132-
# http://stackoverflow.com/a/4631593
133-
res.json [].concat (i.pages for i in install)...
134-
135-
app.get route('plugins'), (req, res) ->
136-
glob "wiki-plugin-*", {cwd: argv.packageDir}, (err, files) ->
137-
return res.e err if err
138-
async.map files||[], info, (err, install) ->
139-
return res.e err if err
140-
res.json {install, bundle}
141-
142-
app.post route('plugins'), (req, res) ->
143-
payload = {bundle}
144-
145-
installed = (cb) ->
146-
files = ("wiki-plugin-#{plugin}" for plugin in req.body.plugins||[])
147-
async.map files||[], info, (err, install) ->
148-
payload.install = install; cb()
149-
150-
published = (cb) ->
151-
async.map req.body.plugins||[], view, (err, results) ->
152-
payload.publish = results; cb()
153-
154-
async.parallel [installed, published], (err) ->
155-
res.json payload
156-
157-
app.get route('view/:pkg'), (req, res) ->
158-
if /^\w+$/.test(req.params.pkg)
159-
pkg = "wiki-plugin-#{req.params.pkg}"
160-
res.setHeader 'Content-Type', 'application/json'
161-
execFile('npm', ['view', "#{pkg}", '--json']).stdout.pipe(res)
162-
163-
app.post route('install'), admin, (req, res) ->
164-
if /^\w+$/.test(req.body.plugin) and /^[\w.-]+$/.test(req.body.version)
165-
pkg = "wiki-plugin-#{req.body.plugin}@#{req.body.version}"
166-
console.log "plugmatic installing #{pkg}"
167-
execFile 'npm', ['install', "#{pkg}", '--json'], {cwd: argv.packageDir+'/..'}, (err, stdout, stderr) ->
168-
try npm = JSON.parse stdout
169-
if err
170-
res.status(400).json {error: 'server unable to install plugin', npm, stderr}
171-
else
172-
info "wiki-plugin-#{req.body.plugin}", (err, row) ->
173-
res.json {installed: req.body.version, npm, stderr, row}
174-
175-
app.post route('restart'), admin, (req, res) ->
176-
console.log 'plugmatic exit to restart'
177-
res.sendStatus 200
178-
process.exit 0
179-
180-
181-
module.exports = {startServer}
1+
/*
2+
* decaffeinate suggestions:
3+
* DS101: Remove unnecessary use of Array.from
4+
* DS102: Remove unnecessary code created because of implicit returns
5+
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
6+
*/
7+
// plugmatic plugin, server-side component
8+
// These handlers are launched with the wiki server.
9+
10+
const fs = require('fs');
11+
const glob = require('glob');
12+
const asyncLib = require('async');
13+
const jsonfile = require('jsonfile');
14+
const https = require('https');
15+
const {
16+
execFile
17+
} = require('child_process');
18+
19+
20+
const github = function(path, done) {
21+
const options = {
22+
host: 'raw.githubusercontent.com',
23+
port: 443,
24+
method: 'GET',
25+
path
26+
};
27+
try {
28+
const req = https.get(options, function(res) {
29+
res.setEncoding('utf8');
30+
let data = '';
31+
res.on('error', () => done(null));
32+
res.on('timeout', () => done(null));
33+
res.on('data', d => data += d);
34+
return res.on('end', () => done(data));
35+
});
36+
return req.on('error', () => done(null));
37+
} catch (e) {
38+
return done(null);
39+
}
40+
};
41+
42+
// http://www.sebastianseilund.com/nodejs-async-in-practice
43+
44+
const startServer = function(params) {
45+
const {
46+
app
47+
} = params;
48+
const {
49+
argv
50+
} = params;
51+
let bundle = null;
52+
53+
github('/fedwiki/wiki/master/package.json', data => bundle = {
54+
date: Date.now(),
55+
data: JSON.parse(data||'{"dependencies":{}}')
56+
});
57+
58+
const route = endpoint => `/plugin/plugmatic/${endpoint}`;
59+
const path = file => `${argv.packageDir}/${file}`;
60+
61+
62+
const info = function(file, done) {
63+
const plugin = file.slice(12);
64+
const site = {plugin};
65+
66+
const birth = cb => fs.stat(path(`${file}/client/${plugin}.js`), function(err, stat) {
67+
site.birth = stat?.birthtime?.getTime(); return cb();
68+
});
69+
const pages = function(cb) {
70+
var synopsis = (slug, cb2) => jsonfile.readFile(path(`${file}/pages/${slug}`), {throws:false}, function(err, page) {
71+
const title = page.title || slug;
72+
synopsis = page.story?.[0]?.text || page.story?.[1]?.text || 'empty';
73+
return cb2(null, {file, slug, title, synopsis});
74+
});
75+
return fs.readdir(path(`${file}/pages`), (err, slugs) => asyncLib.map(slugs||[], synopsis, function(err, pages) {
76+
site.pages = pages; return cb();
77+
}));
78+
};
79+
const packagejson = cb => jsonfile.readFile(path(`${file}/package.json`), {throws:false}, function(err, packagejson) {
80+
site.package = packagejson; return cb();
81+
});
82+
const factory = cb => jsonfile.readFile(path(`${file}/factory.json`), {throws:false}, function(err, factory) {
83+
site.factory = factory; return cb();
84+
});
85+
const authors = cb => fs.readFile(path(`${file}/AUTHORS.txt`), 'utf-8', function(err, authors) {
86+
site.authors = authors; return cb();
87+
});
88+
// persona = (cb) ->
89+
// fs.readFile path("#{file}/status/persona.identity"),'utf8', (err, identity) ->
90+
// site.persona = identity; cb()
91+
// openid = (cb) ->
92+
// fs.readFile path("#{file}/status/open_id.identity"),'utf8', (err, identity) ->
93+
// site.openid = identity; cb()
94+
return asyncLib.series([birth,authors,packagejson,factory,pages], err => done(null, site));
95+
};
96+
97+
const plugmap = done => glob("wiki-plugin-*", {cwd: argv.packageDir}, function(err, files) {
98+
if (err) { return done(err,null); }
99+
return asyncLib.map(files||[], info, function(err, install) {
100+
if (err) { return done(err,null); }
101+
return done(null, install);
102+
});
103+
});
104+
105+
106+
const view = function(plugin, done) {
107+
if (/^\w+$/.test(plugin)) {
108+
const pkg = `wiki-plugin-${plugin}`;
109+
return execFile('npm', ['view', `${pkg}`, '--json'], function(err, stdout, stderr) {
110+
let npm;
111+
try { npm = JSON.parse(stdout); } catch (error) {}
112+
return done(null, {plugin, pkg, npm});
113+
});
114+
}
115+
};
116+
117+
const farm = function(req, res, next) {
118+
if (argv.f) {
119+
return next();
120+
} else {
121+
return res.status(404).send({error: 'service requires farm mode'});
122+
}
123+
};
124+
125+
var admin = function(req, res, next) {
126+
if (app.securityhandler.isAdmin(req)) {
127+
return next();
128+
} else {
129+
let user;
130+
if (!argv.admin) { admin = "none specified"; }
131+
if (!req.session?.passport?.user && !req.session?.email && !req.session?.friend) { user = "not logged in"; }
132+
return res.status(403).send({error: 'service requires admin user', admin, user});
133+
}
134+
};
135+
136+
app.get(route('page/:slug.json'), (req, res) => plugmap(function(err, install) {
137+
for (var i of Array.from(install)) {
138+
for (var p of Array.from(i.pages)) {
139+
if (p.slug === req.params.slug) {
140+
return jsonfile.readFile(path(`${p.file}/pages/${p.slug}`), {throws:false}, (err, page) => res.json(page));
141+
}
142+
}
143+
}
144+
return res.sendStatus(404);
145+
}));
146+
147+
app.get(route('file/:file/slug/:slug'), (req, res) => jsonfile.readFile(path(`${req.params.file}/pages/${req.params.slug}`), {throws:false}, function(err, page) {
148+
if (err) {
149+
return res.sendStatus(404);
150+
} else {
151+
return res.json(page);
152+
}
153+
}));
154+
155+
app.get(route('sitemap.json'), (req, res) => plugmap((err, install) => // http://stackoverflow.com/a/4631593
156+
res.json(
157+
[].concat(...Array.from(((Array.from(install).map((i) => i.pages))) || []))
158+
)));
159+
160+
app.get(route('plugins'), (req, res) => glob("wiki-plugin-*", {cwd: argv.packageDir}, function(err, files) {
161+
if (err) { return res.e(err); }
162+
return asyncLib.map(files||[], info, function(err, install) {
163+
if (err) { return res.e(err); }
164+
return res.json({install, bundle});
165+
});
166+
}));
167+
168+
app.post(route('plugins'), function(req, res) {
169+
const payload = {bundle};
170+
171+
const installed = function(cb) {
172+
const files = (Array.from(req.body.plugins||[]).map((plugin) => `wiki-plugin-${plugin}`));
173+
return asyncLib.map(files||[], info, function(err, install) {
174+
payload.install = install; return cb();
175+
});
176+
};
177+
178+
const published = cb => asyncLib.map(req.body.plugins||[], view, function(err, results) {
179+
payload.publish = results; return cb();
180+
});
181+
182+
return asyncLib.parallel([installed, published], err => res.json(payload));
183+
});
184+
185+
app.get(route('view/:pkg'), function(req, res) {
186+
if (/^\w+$/.test(req.params.pkg)) {
187+
const pkg = `wiki-plugin-${req.params.pkg}`;
188+
res.setHeader('Content-Type', 'application/json');
189+
return execFile('npm', ['view', `${pkg}`, '--json']).stdout.pipe(res);
190+
}
191+
});
192+
193+
app.post(route('install'), admin, function(req, res) {
194+
if (/^\w+$/.test(req.body.plugin) && /^[\w.-]+$/.test(req.body.version)) {
195+
const pkg = `wiki-plugin-${req.body.plugin}@${req.body.version}`;
196+
console.log(`plugmatic installing ${pkg}`);
197+
return execFile('npm', ['install', `${pkg}`, '--json'], {cwd: argv.packageDir+'/..'}, function(err, stdout, stderr) {
198+
let npm;
199+
try { npm = JSON.parse(stdout); } catch (error) {}
200+
if (err) {
201+
return res.status(400).json({error: 'server unable to install plugin', npm, stderr});
202+
} else {
203+
return info(`wiki-plugin-${req.body.plugin}`, (err, row) => res.json({installed: req.body.version, npm, stderr, row}));
204+
}
205+
});
206+
}
207+
});
208+
209+
return app.post(route('restart'), admin, function(req, res) {
210+
console.log('plugmatic exit to restart');
211+
res.sendStatus(200);
212+
return process.exit(0);
213+
});
214+
};
215+
216+
217+
module.exports = {startServer};

0 commit comments

Comments
 (0)