Skip to content

Commit

Permalink
v2.10.0
Browse files Browse the repository at this point in the history
  • Loading branch information
akaJes committed May 17, 2018
2 parents b731f07 + ac0e1ff commit 15e10a8
Show file tree
Hide file tree
Showing 18 changed files with 1,347 additions and 3 deletions.
3 changes: 3 additions & 0 deletions app/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ var qr = require('qr-image');
var machineId = require('node-machine-id').machineId;

const store = require('./store');
store.mods.editor && (store.mods.editor.root = () => git.root())

var server = http.Server(app);
var visitor = ua('UA-99239389-1');
Expand Down Expand Up @@ -224,6 +225,8 @@ app.post('/set/:file/:name/:prop/:value', function (req, res) {

app.use('/', require('./services'));

require('./services/ot').init(server, '/ws');

var serve = (http, port) =>
new Promise((resolve, reject) => {
http.on('error', reject);
Expand Down
99 changes: 99 additions & 0 deletions app/services/editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
const router = module.exports = require('express').Router();
const git = require('../git-tool');
const store = require('../store').mods.editor;
const path = require('path');
const promisify = require('../helpers').promisify;
const fs = require('fs');
const formidable = require('formidable');

const safePath = val => decodeURI(val).replace(/|\.\.|\/\//g, '');
const getRoot = req => Promise.resolve(store.root(req))

//create
router.post('/file/*', (req, res) => {
const f = req.query.type == 'file';
const p = safePath(req.url.slice(5));
return getRoot(req)
.then(root => promisify(f && fs.writeFile || fs.mkdir)(path.join(root, p), f ? '' : 0o777)) //TODO: check if exists
.then(a => ({id: p}))
.catch(e => res.status(501).send(e.message))
.then(data => res.send(data))
})

//remove
router.delete('/file/*', (req, res) => {
const p = safePath(req.url.slice(5));
return getRoot(req)
.then(root => promisify(fs.stat)(path.join(root, p)).then(stats => promisify(stats.isDirectory() ? fs.rmdir : fs.unlink)(path.join(root, p)) ))
.then(a => ({id: p}))
.catch(e => res.status(501).send(e.message))
.then(data => res.send(data))
})

//move //TODO check if destenation not exists ?
router.put('/file/*', (req, res) => {
const p = safePath(req.url.slice(5));
const t = safePath(req.body.to);
return getRoot(req)
.then(root => promisify(fs.rename)(path.join(root, p), path.join(root, t)))
.then(a => ({id: t}))
.catch(e => res.status(501).send(e.message))
.then(data => res.send(data))
})

//TODO:copy

//list
router.get('/tree', function(req, res) {
var dir = req.query.id == '#' && '/' || req.query.id || '';
dir = dir.replace(/\.\./g, '');
return getRoot(req)
.then(root => promisify(fs.readdir)(path.join(root, dir))
.then(list => list.filter(name => name && (name != '.' || name != '..')))
.then(list => Promise.all(list.map(name => promisify(fs.stat)(path.join(root, dir, name))
.then(stats => ({
children: stats.isDirectory(),
type: stats.isDirectory() ? 'default' : "file",
text: name,
id: path.join(dir, name),
// icon: stats.isDirectory() ? 'jstree-folder' : "jstree-file",
}))))
)
)
.then(list => dir != '/' && list || {text: store.name(req), children: list, id: '/', type: 'default', state: {opened: true, disabled: true}})
.catch(e => res.status(501).send(e.message))
.then(data => res.send(data))
})

//content
router.get('/file/*', function(req, res) {
const p = safePath(req.url.slice(5));
return getRoot(req)
.then(root => promisify(fs.stat)(path.join(root, p)).then(stats => !stats.isDirectory() && promisify(fs.readFile)(path.join(root, p)) || '' ))
.catch(e => res.status(501).send(e.message))
.then(data => res.send(data))
})

const parseForm = req => new Promise((resolve, reject) => {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
return err && reject(err) || resolve([fields, files]);
})
})

router.post('/upload/*', function(req, res) {
const p = safePath(req.url.slice(7));
return getRoot(req)
.then(root => parseForm(req).then(ff => promisify(fs.rename)(ff[1].data.path, path.join(root, p)).then(a => p) ))
.catch(e => res.status(501).send(e.message))
.then(data => res.send(data))
});


//git file TODO: git for multiproject
router.get('/git/*', function(req, res) {
git.Tag()
.then(tag => git.Show(tag, req.originalUrl.replace(/.*git\//, '')))
.catch(e => res.status(501).send(e.message))
.then(data => res.send(data))
})
3 changes: 2 additions & 1 deletion app/services/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
const router = module.exports = require('express').Router();
const store = require('../store');

//router.use('/s/editor', require('./editor'));
router.use('/', require('./sse'));
if (store.mods.editor)
router.use('/s/editor', require('./editor'));
if (store.mods.upnp)
router.use('/upnp', require('./upnp'));
if (store.mods.serial)
Expand Down
51 changes: 51 additions & 0 deletions app/services/ot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const fs = require('fs');
const path = require('path');
const sio = require('socket.io');
const ot = require('ot');
const store = require('../store').mods.editor;
const promisify = require('../helpers').promisify;

var ns = {};
const getFile = file => store.root().then(root => promisify(fs.readFile)(path.join(root, file)))
const setFile = (file, data) => store.root().then(root => promisify(fs.writeFile)(path.join(root, file), data))

exports.init = (server, url) => {
const io = new sio(server, {path: url});
io.on('connection', function(socket) {
socket.on('ns', function (docId) {
if (ns[docId])
socket.emit('ns', docId);
else {
getFile(docId)
.then(text => {
var doc = ns[docId] = new ot.EditorSocketIOServer(text.toString(), 0, docId)
socket.emit('ns', docId);
io.of(docId)
.on('connection', function(socket) {
function clients(mode) {
socket.broadcast.in(docId).emit('clients', {clients: doc.users, mode: mode});
}
doc.getClient(socket.id);
doc.addClient(socket);
clients('enter');
socket.in(docId)
.on('disconnect', function() {
console.log('disconnect');
delete doc.users[socket.id];
clients('leave');
})
.on('name', function (name) {
doc.setName(socket, name);
console.log('set name')
clients('name');
})
.on('operation', function (name) {
console.log('saving...');
setFile(docId, doc.document);
});
})
})
}
});
});
}
4 changes: 4 additions & 0 deletions app/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ exports.config = {

exports.mods = {
sse: {},
editor: {
root(req) {}, //replace it!
name(req) { return 'marlin-conf' },
},
serial: {}, // comment for disabling
upnp: {}, // comment for disabling
};
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@
},
"homepage": "https://github.com/akaJes/marlin-config#readme",
"dependencies": {
"ace-builds": "^1.3.3",
"body-parser": "^1.17.2",
"bootstrap": "4.0.0-alpha.6",
"cropper": "^3.1.5",
"data-store": "^1.0.0",
"diff-match-patch": "^1.0.0",
"express": "^4.16.2",
"fix-path": "^2.1.0",
"font-awesome": "^4.7.0",
Expand All @@ -70,13 +72,15 @@
"jquery": "^3.3.1",
"jquery-ui-dist": "^1.12.1",
"js-yaml": "^3.8.4",
"jstree": "^3.3.5",
"marked": "^0.3.16",
"mkdirp": "^0.5.1",
"moment": "^2.20.1",
"nat-upnp": "^1.1.1",
"node-machine-id": "^1.1.10",
"node-notifier": "^5.2.1",
"opn": "^5.2.0",
"ot": "git+https://github.com/Operational-Transformation/ot.js.git",
"platformio-node-helpers": "^0.4.3",
"qr-image": "^3.2.0",
"rtcmulticonnection-v3": "^3.4.4",
Expand All @@ -92,7 +96,7 @@
"yauzl": "^2.9.1",
"yazl": "^2.4.3"
},
"devDependenciesOff": {
"devDependencies": {
"devtron": "^1.4.0",
"electron": "=1.7.10",
"electron-builder": "^20.2.0",
Expand Down
Loading

0 comments on commit 15e10a8

Please sign in to comment.