Initial import
This commit is contained in:
76
app/ws/Socket.js
Normal file
76
app/ws/Socket.js
Normal file
@@ -0,0 +1,76 @@
|
||||
const uuid = require('uuid').v4
|
||||
const { Message } = require('../shared')
|
||||
const { Injectable } = require('flitter-di')
|
||||
|
||||
class Socket extends Injectable {
|
||||
static get services() {
|
||||
return [...super.services, 'app', 'output']
|
||||
}
|
||||
|
||||
messages = []
|
||||
|
||||
constructor(socket) {
|
||||
super()
|
||||
this.socket = socket
|
||||
this.uuid = uuid()
|
||||
this.session = {}
|
||||
|
||||
this.socket.on('message', msg => this.on_message(msg))
|
||||
}
|
||||
|
||||
ping() {
|
||||
this.send(Message.route('meta.ping').expect_response())
|
||||
}
|
||||
|
||||
send(message) {
|
||||
this.output.debug(message)
|
||||
|
||||
if ( typeof message === 'string' ) {
|
||||
this.socket.send(message)
|
||||
return
|
||||
}
|
||||
|
||||
if ( message.needs_response ) {
|
||||
this.messages.push(message)
|
||||
}
|
||||
|
||||
const serial = message.serialize()
|
||||
this.socket.send(serial)
|
||||
}
|
||||
|
||||
async on_message(msg) {
|
||||
this.output.info(msg)
|
||||
const message = new Message(msg)
|
||||
const response = new Message()
|
||||
message.socket = this
|
||||
|
||||
if ( message.is_response() ) {
|
||||
// Try to find the message that sent the request
|
||||
const request = this.messages.find(x => x.uuid() === message.response_to())
|
||||
if ( request ) {
|
||||
await request._response_callback(message)
|
||||
request.has_response = true;
|
||||
} else {
|
||||
this.send(
|
||||
response.response_to(message.uuid())
|
||||
.error(Errors.InvalidReplyUUID)
|
||||
)
|
||||
}
|
||||
|
||||
this.messages = this.messages.filter(x => !x.has_response)
|
||||
} else {
|
||||
let handler;
|
||||
try {
|
||||
handler = require(`./routes/${message.route()}`)
|
||||
} catch (e) {}
|
||||
|
||||
if ( !handler ) {
|
||||
return this.send(socket, response.error(Errors.InvalidMessageRoute))
|
||||
}
|
||||
|
||||
await handler(message, this.app.di().container.proxy())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = Socket
|
||||
35
app/ws/StreamTake.js
Normal file
35
app/ws/StreamTake.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const stream = require('stream')
|
||||
const util = require('util')
|
||||
|
||||
const Transform = stream.Transform
|
||||
|
||||
function Take(options) {
|
||||
// allow use without new
|
||||
if (!(this instanceof Take)) {
|
||||
return new Take(options);
|
||||
}
|
||||
|
||||
this._toTake = options.take || undefined
|
||||
|
||||
// init Transform
|
||||
Transform.call(this, options);
|
||||
}
|
||||
|
||||
util.inherits(Take, Transform);
|
||||
|
||||
Take.prototype._transform = function (chunk, enc, cb) {
|
||||
if ( typeof this._toTake == 'undefined' ) {
|
||||
this.push(chunk)
|
||||
}
|
||||
else if (this._toTake > chunk.length) {
|
||||
this._toTake -= chunk.length;
|
||||
this.push(chunk)
|
||||
} else {
|
||||
if (this._toTake !== chunk.length) this.push(chunk.slice(0, this._toTake))
|
||||
this._toTake = 0;
|
||||
}
|
||||
|
||||
cb();
|
||||
};
|
||||
|
||||
module.exports = Take;
|
||||
52
app/ws/routes/fs.create.js
Normal file
52
app/ws/routes/fs.create.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const { Errors } = require('../../shared')
|
||||
const { NodeDescriptorType } = require('../../enum')
|
||||
|
||||
module.exports = exports = async (message, di) => {
|
||||
const new_fd = (node_uuid) => {
|
||||
if ( !message.socket.session.last_file_descriptor ) {
|
||||
message.socket.session.last_file_descriptor = 0
|
||||
message.socket.session.file_descriptors = {}
|
||||
}
|
||||
|
||||
message.socket.session.last_file_descriptor += 1
|
||||
message.socket.session.file_descriptors[message.socket.session.last_file_descriptor] = node_uuid
|
||||
return message.socket.session.last_file_descriptor
|
||||
}
|
||||
|
||||
const Node = di.models.get('fs:Node')
|
||||
const { path, mode } = message.data()
|
||||
|
||||
if ( !path ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeDoesNotExist)
|
||||
)
|
||||
}
|
||||
|
||||
if ( path === '/' ) {
|
||||
return message.send_response(
|
||||
message.fresh.error(Errors.NodeAlreadyExists)
|
||||
)
|
||||
}
|
||||
|
||||
const existing_node = await Node.get_path(path, message.socket.session.overlay_name || 'mainline')
|
||||
if ( existing_node ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeAlreadyExists)
|
||||
)
|
||||
}
|
||||
|
||||
const [pied_parent_path, pied_name] = Node.path_parts(path)
|
||||
const node = new Node({
|
||||
pied_name,
|
||||
pied_parent_path,
|
||||
overlay_name: message.socket.session.overlay_name || 'mainline',
|
||||
mode: 33188, // TODO account for the mode from the client!
|
||||
descriptor_type: NodeDescriptorType.File,
|
||||
})
|
||||
|
||||
await node.save()
|
||||
|
||||
message.send_response(
|
||||
message.fresh().data({ node: node.to_api(), descriptor: new_fd(node.uuid) })
|
||||
)
|
||||
}
|
||||
26
app/ws/routes/fs.getattr.js
Normal file
26
app/ws/routes/fs.getattr.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const { Errors } = require('../../shared')
|
||||
|
||||
module.exports = exports = async (message, di) => {
|
||||
const Node = di.models.get('fs:Node')
|
||||
const { path } = message.data()
|
||||
|
||||
let data
|
||||
if ( path === '/' ) {
|
||||
const root = await Node.get_root()
|
||||
data = root.to_api()
|
||||
} else {
|
||||
const node = await Node.get_path(path, message.socket.session.overlay_name || 'mainline')
|
||||
|
||||
if ( !node ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeDoesNotExist)
|
||||
)
|
||||
}
|
||||
|
||||
data = node.to_api()
|
||||
}
|
||||
|
||||
message.send_response(
|
||||
message.fresh().data({ node: data })
|
||||
)
|
||||
}
|
||||
42
app/ws/routes/fs.mkdir.js
Normal file
42
app/ws/routes/fs.mkdir.js
Normal file
@@ -0,0 +1,42 @@
|
||||
const { Errors } = require('../../shared')
|
||||
const { NodeDescriptorType } = require('../../enum')
|
||||
|
||||
module.exports = exports = async (message, di) => {
|
||||
const Node = di.models.get('fs:Node')
|
||||
const { path, mode } = message.data()
|
||||
|
||||
if ( !path ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeDoesNotExist)
|
||||
)
|
||||
}
|
||||
|
||||
if ( path === '/' ) {
|
||||
return message.send_response(
|
||||
message.fresh.error(Errors.NodeAlreadyExists)
|
||||
)
|
||||
}
|
||||
|
||||
const existing_node = await Node.get_path(path, message.socket.session.overlay_name || 'mainline')
|
||||
if ( existing_node ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeAlreadyExists)
|
||||
)
|
||||
}
|
||||
|
||||
const [pied_parent_path, pied_name] = Node.path_parts(path)
|
||||
const node = new Node({
|
||||
pied_name,
|
||||
pied_parent_path,
|
||||
overlay_name: message.socket.session.overlay_name || 'mainline',
|
||||
mode: 16877, // TODO account for the mode from the client!
|
||||
descriptor_type: NodeDescriptorType.Directory,
|
||||
size: 100,
|
||||
})
|
||||
|
||||
await node.save()
|
||||
|
||||
message.send_response(
|
||||
message.fresh().data({ node: node.to_api() })
|
||||
)
|
||||
}
|
||||
33
app/ws/routes/fs.open.js
Normal file
33
app/ws/routes/fs.open.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const { Errors } = require('../../shared')
|
||||
const { NodeDescriptorType } = require('../../enum')
|
||||
|
||||
module.exports = exports = async (message, di) => {
|
||||
const send_error = (err) => message.send_response(
|
||||
message.fresh().error(err)
|
||||
)
|
||||
|
||||
const new_fd = (node_uuid) => {
|
||||
if ( !message.socket.session.last_file_descriptor ) {
|
||||
message.socket.session.last_file_descriptor = 0
|
||||
message.socket.session.file_descriptors = {}
|
||||
}
|
||||
|
||||
message.socket.session.last_file_descriptor += 1
|
||||
message.socket.session.file_descriptors[message.socket.session.last_file_descriptor] = node_uuid
|
||||
return message.socket.session.last_file_descriptor
|
||||
}
|
||||
|
||||
const Node = di.models.get('fs:Node')
|
||||
const { path, flags } = message.data()
|
||||
|
||||
if ( !path ) return send_error(Errors.NodeDoesNotExist)
|
||||
if ( path === '/' ) return send_error(Errors.IsDirectoryDescriptor)
|
||||
|
||||
const node = await Node.get_path(path, message.socket.session.overlay_name || 'mainline')
|
||||
if ( !node ) send_error(Errors.NodeDoesNotExist)
|
||||
if ( node.descriptor_type === NodeDescriptorType.Directory ) send_error(Errors.IsDirectoryDescriptor)
|
||||
|
||||
message.send_response(
|
||||
message.fresh().data({ node: node.to_api(), descriptor: new_fd(node.uuid) })
|
||||
)
|
||||
}
|
||||
23
app/ws/routes/fs.readdir.js
Normal file
23
app/ws/routes/fs.readdir.js
Normal file
@@ -0,0 +1,23 @@
|
||||
const { Errors } = require('../../shared')
|
||||
|
||||
module.exports = exports = async (message, di) => {
|
||||
const Node = di.models.get('fs:Node')
|
||||
const { path } = message.data()
|
||||
|
||||
if ( path !== '/' ) {
|
||||
// If the path isn't the root of the workspace, then make
|
||||
// sure that the parent node actually exists
|
||||
const node = await Node.get_path(path, message.socket.session.overlay_name || 'mainline')
|
||||
if ( !node ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeDoesNotExist)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const nodes = await Node.list_path(path, message.socket.session.overlay_name || 'mainline')
|
||||
|
||||
message.send_response(
|
||||
message.fresh().data({ nodes })
|
||||
)
|
||||
}
|
||||
11
app/ws/routes/fs.release.js
Normal file
11
app/ws/routes/fs.release.js
Normal file
@@ -0,0 +1,11 @@
|
||||
module.exports = exports = async (message, di) => {
|
||||
const { descriptor } = message.data()
|
||||
|
||||
if ( message.socket.session.file_descriptors ) {
|
||||
delete message.socket.session.file_descriptors[descriptor]
|
||||
}
|
||||
|
||||
message.send_response(
|
||||
message.fresh()
|
||||
)
|
||||
}
|
||||
69
app/ws/routes/fs.rename.js
Normal file
69
app/ws/routes/fs.rename.js
Normal file
@@ -0,0 +1,69 @@
|
||||
const { Errors } = require('../../shared')
|
||||
const { NodeDescriptorType } = require('../../enum')
|
||||
|
||||
module.exports = exports = async (message, di) => {
|
||||
const Node = di.models.get('fs:Node')
|
||||
const { source, destination } = message.data()
|
||||
|
||||
if ( !source ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeDoesNotExist)
|
||||
)
|
||||
}
|
||||
|
||||
if ( source === '/' ) {
|
||||
return message.send_response(
|
||||
message.fresh.error(Errors.NodePermissionFail)
|
||||
)
|
||||
}
|
||||
|
||||
const node = await Node.get_path(source, message.socket.session.overlay_name || 'mainline')
|
||||
if ( !node ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeDoesNotExist)
|
||||
)
|
||||
}
|
||||
|
||||
// make sure the move-to destination is valid
|
||||
const [pied_parent_path, pied_name] = Node.path_parts(destination)
|
||||
if ( pied_parent_path !== '/' ) {
|
||||
const parent_node = await Node.get_path(pied_parent_path, message.socket.session.overlay_name || 'mainline')
|
||||
if ( !parent_node ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeDoesNotExist)
|
||||
)
|
||||
}
|
||||
|
||||
if ( parent_node.descriptor_type !== NodeDescriptorType.Directory ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NotDirectoryDescriptor)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const existing_target = await Node.get_path(destination, message.socket.session.overlay_name || 'mainline')
|
||||
if ( existing_target ) {
|
||||
// If we're moving to an existing target, overwrite that target
|
||||
const all_desc = await existing_target.all_descendants(message.socket.session.overlay_name || 'mainline')
|
||||
await Promise.all(all_desc.map(desc => {
|
||||
desc.deleted = true
|
||||
return desc.save()
|
||||
}))
|
||||
|
||||
existing_target.deleted = true
|
||||
await existing_target.save()
|
||||
}
|
||||
const moved_desc = await node.all_descendants(message.socket.session.overlay_name || 'mainline')
|
||||
await Promise.all(moved_desc.map(moved_node => {
|
||||
moved_node.pied_parent_path = moved_node.pied_parent_path.replace(source, destination)
|
||||
return moved_node.save()
|
||||
}))
|
||||
|
||||
node.pied_parent_path = pied_parent_path
|
||||
node.pied_name = pied_name
|
||||
await node.save()
|
||||
|
||||
message.send_response(
|
||||
message.fresh()
|
||||
)
|
||||
}
|
||||
51
app/ws/routes/fs.rmdir.js
Normal file
51
app/ws/routes/fs.rmdir.js
Normal file
@@ -0,0 +1,51 @@
|
||||
const { Errors } = require('../../shared')
|
||||
const { NodeDescriptorType } = require('../../enum')
|
||||
|
||||
module.exports = exports = async (message, di) => {
|
||||
const Node = di.models.get('fs:Node')
|
||||
const { path } = message.data()
|
||||
|
||||
if ( !path ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeDoesNotExist)
|
||||
)
|
||||
}
|
||||
|
||||
if ( path === '/' ) {
|
||||
return message.send_response(
|
||||
message.fresh.error(Errors.NodePermissionFail)
|
||||
)
|
||||
}
|
||||
|
||||
const node = await Node.get_path(path, message.socket.session.overlay_name || 'mainline')
|
||||
if ( !node ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeDoesNotExist)
|
||||
)
|
||||
}
|
||||
|
||||
if ( node.descriptor_type !== NodeDescriptorType.Directory ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NotDirectoryDescriptor)
|
||||
)
|
||||
}
|
||||
|
||||
const child = await Node.findOne({
|
||||
pied_parent_path: path,
|
||||
overlay_name: message.socket.session.overlay_name || 'mainline',
|
||||
deleted: false,
|
||||
})
|
||||
|
||||
if ( child ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeNotEmpty)
|
||||
)
|
||||
}
|
||||
|
||||
node.deleted = true
|
||||
await node.save()
|
||||
|
||||
message.send_response(
|
||||
message.fresh()
|
||||
)
|
||||
}
|
||||
39
app/ws/routes/fs.unlink.js
Normal file
39
app/ws/routes/fs.unlink.js
Normal file
@@ -0,0 +1,39 @@
|
||||
const { Errors } = require('../../shared')
|
||||
const { NodeDescriptorType } = require('../../enum')
|
||||
|
||||
module.exports = exports = async (message, di) => {
|
||||
const Node = di.models.get('fs:Node')
|
||||
const { path } = message.data()
|
||||
|
||||
if ( !path ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeDoesNotExist)
|
||||
)
|
||||
}
|
||||
|
||||
if ( path === '/' ) {
|
||||
return message.send_response(
|
||||
message.fresh.error(Errors.NodePermissionFail)
|
||||
)
|
||||
}
|
||||
|
||||
const node = await Node.get_path(path, message.socket.session.overlay_name || 'mainline')
|
||||
if ( !node ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeDoesNotExist)
|
||||
)
|
||||
}
|
||||
|
||||
if ( node.descriptor_type !== NodeDescriptorType.File ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.IsDirectoryDescriptor)
|
||||
)
|
||||
}
|
||||
|
||||
node.deleted = true
|
||||
await node.save()
|
||||
|
||||
message.send_response(
|
||||
message.fresh()
|
||||
)
|
||||
}
|
||||
19
app/ws/routes/meta.authenticate.js
Normal file
19
app/ws/routes/meta.authenticate.js
Normal file
@@ -0,0 +1,19 @@
|
||||
module.exports = exports = async (message, di) => {
|
||||
const Token = di.models.get('Token')
|
||||
const { token_value } = message.data()
|
||||
|
||||
const token = await Token.findOne({ active: true, token_value })
|
||||
if ( token ) {
|
||||
message.socket.session.is_auth = true
|
||||
message.socket.session.token_value = token_value
|
||||
message.socket.session.user_uuid = token.user_uuid
|
||||
|
||||
return message.send_response(
|
||||
message.fresh().data({ is_auth: true })
|
||||
)
|
||||
}
|
||||
|
||||
return message.send_response(
|
||||
message.fresh().data({ is_auth: false })
|
||||
)
|
||||
}
|
||||
4
app/ws/routes/meta.ping.js
Normal file
4
app/ws/routes/meta.ping.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = exports = async (message, di) => {
|
||||
console.log('Received ping!');
|
||||
message.send_response(message.fresh())
|
||||
}
|
||||
34
app/ws/routes/stream.getfd.js
Normal file
34
app/ws/routes/stream.getfd.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const { NodeDescriptorType } = require('../../enum')
|
||||
const { Errors } = require('../../shared')
|
||||
|
||||
module.exports = exports = async (message, di) => {
|
||||
const Node = di.models.get('fs:Node')
|
||||
const { descriptor } = message.data()
|
||||
|
||||
if ( !descriptor || !message.socket.session.file_descriptors[descriptor] ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NoSuchDescriptor)
|
||||
)
|
||||
}
|
||||
|
||||
const node = await Node.findOne({
|
||||
deleted: false,
|
||||
descriptor_type: NodeDescriptorType.File,
|
||||
uuid: message.socket.session.file_descriptors[descriptor],
|
||||
})
|
||||
|
||||
if ( !node ) {
|
||||
return message.send_response(
|
||||
message.fresh().error(Errors.NodeDoesNotExist)
|
||||
)
|
||||
}
|
||||
|
||||
const data = {
|
||||
node_uuid: node.uuid,
|
||||
socket_uuid: message.socket.uuid,
|
||||
}
|
||||
|
||||
message.send_response(
|
||||
message.fresh().data(data)
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user