Initial import

This commit is contained in:
2020-11-26 19:57:37 -06:00
commit 81032e3b0b
33 changed files with 5986 additions and 0 deletions

76
app/ws/Socket.js Normal file
View 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
View 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;

View 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) })
)
}

View 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
View 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
View 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) })
)
}

View 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 })
)
}

View 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()
)
}

View 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
View 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()
)
}

View 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()
)
}

View 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 })
)
}

View File

@@ -0,0 +1,4 @@
module.exports = exports = async (message, di) => {
console.log('Received ping!');
message.send_response(message.fresh())
}

View 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)
)
}