Skip to content

Instantly share code, notes, and snippets.

@phoboslab
Created June 21, 2021 06:33
Show Gist options
  • Save phoboslab/0bf09acb2ea4912d621ae80c439a4bba to your computer and use it in GitHub Desktop.
Save phoboslab/0bf09acb2ea4912d621ae80c439a4bba to your computer and use it in GitHub Desktop.
Impact2 Weltmeister Server
'use strict';
let http = require('http'),
url = require('url'),
querystring = require('querystring'),
fs = require('fs'),
editorIndex = 'editor/editor.html',
port = parseInt(process.argv[2] || 8080, 10);
let API = {
glob: function(params, body, callback) {
let dir = params.dir ? params.dir.replace(/\/$/, '') : '';
fs.readdir('./' + dir, function(err, files){
if (err) {
return callback('dir listing failed for ./' + dir);
}
let parent = dir.replace(/\/?[^\/]*$/,'');
let ret = {current: dir, parent: parent, dirs: [], files: []},
typeMatch = params.type
? new RegExp('\\.' + params.type + '$')
: null;
for (let i = 0; i < files.length; i++) {
let fileName = files[i],
filePath = (dir && dir+'/') + fileName;
if (fileName.match(/^\./)) {
continue;
}
if (fs.statSync('./' + filePath).isDirectory()) {
ret.dirs.push({name: fileName, path: filePath});
}
else if (!params.type || fileName.match(typeMatch)) {
ret.files.push({name: fileName, path: filePath});
}
}
callback(null, ret);
});
},
save: function(params, body, callback) {
if (!params.path) {
return callback('no path specified');
}
fs.writeFile(params.path, body, {flag: 'w'}, function(err) {
if (err) {
return callback('error writing file ' + params.path);
}
callback(null, {saved: true});
});
}
};
let utf8 = '; charset=utf-8';
let mime = {
html: 'text/html' + utf8,
htm: 'text/html' + utf8,
json: 'application/json' + utf8,
js: 'application/javascript' + utf8,
jpeg: 'image/jpeg',
jpg: 'image/jpeg',
gif: 'image/gif',
png: 'image/png',
ogg: 'audio/ogg',
mp3: 'audio/mp3',
aac: 'audio/aac',
css: 'text/css' + utf8,
bin: 'application/octet-stream'
};
let serveAPI = function(request, response, name) {
let uri = url.parse(request.url, true),
apiFunc = API[name];
if (!apiFunc) {
return writeError(request, response, 404, 'no such API function: ' + name);
}
console.log('API:', name, uri.query);
let bodyChunks = [];
request.on('data', function(chunk){
bodyChunks.push(chunk);
});
request.on('end', function(){
let body = Buffer.concat(bodyChunks);
apiFunc(uri.query, body, function(err, data){
if (err) {
writeError(request, response, 500, err);
}
else {
response.writeHead(200, {'Content-Type': mime.json});
response.write(JSON.stringify(data));
response.end();
}
});
});
};
let serveStaticFile = function(request, response) {
let uri = querystring.unescape(url.parse(request.url).pathname),
fileName = './' + uri;
if (uri === '/editor') {
fileName = editorIndex;
}
fs.stat(fileName, function(err, stat) {
if (err) {
return writeError(request, response, 404, 'not found');
}
if (stat.isDirectory()) {
fileName += '/index.html';
}
fs.readFile(fileName, 'binary', function(err, file) {
if (err) {
return writeError(request, response, 500, 'internal error');
}
let ext = fileName.match(/\.(\w+)$/);
console.log('200: ' + uri);
response.writeHead(200, {'content-type': (ext && mime[ext[1]]) || mime.bin});
response.write(file, 'binary');
response.end();
});
});
};
let writeError = function(request, response, code, message) {
console.log(code+': ' + request.url);
response.writeHead(code, {'Content-Type': mime.json});
response.write(JSON.stringify({error: {code: code, message: message}}));
response.end();
};
http.createServer(function(request, response) {
let apiMatch = null;
if (apiMatch = request.url.match(/^\/api\/(\w+)/)) {
serveAPI(request, response, apiMatch[1]);
}
else {
serveStaticFile(request, response);
}
}).listen(port);
console.log(
'Impact editor running at: http://localhost:' + port + '/editor\n' +
'CTRL + C to shutdown'
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment