UNPKG

@cocalc/project

Version:
124 lines (111 loc) 5.06 kB
######################################################################### # This file is part of CoCalc: Copyright © 2020 Sagemath, Inc. # License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details ######################################################################### fs = require('fs') temp = require('temp') child_process = require('child_process') async = require('async') winston = require('./logger').getLogger('read-write-files') message = require('@cocalc/util/message') misc_node = require('@cocalc/backend/misc_node') misc = require('@cocalc/util/misc') common = require('./common') ensureContainingDirectoryExists = require('@cocalc/backend/misc/ensure-containing-directory-exists').default writeFile = require("fs/promises").writeFile; ############################################### # Read and write individual files ############################################### # Read a file located in the given project. This will result in an # error if the readFile function fails, e.g., if the file doesn't # exist or the project is not open. We then send the resulting file # over the socket as a blob message. # # Directories get sent as a ".tar.bz2" file. # TODO: should support -- 'tar', 'tar.bz2', 'tar.gz', 'zip', '7z'. and mesg.archive option!!! # exports.read_file_from_project = (socket, mesg) -> #dbg = (m) -> winston.debug("read_file_from_project(path='#{mesg.path}'): #{m}") #dbg() data = undefined path = misc_node.abspath(mesg.path) is_dir = undefined id = undefined archive = undefined stats = undefined async.series([ (cb) -> #dbg("Determine whether the path '#{path}' is a directory or file.") fs.stat path, (err, _stats) -> if err cb(err) else stats = _stats is_dir = stats.isDirectory() cb() (cb) -> # make sure the file isn't too large cb(common.check_file_size(stats.size)) (cb) -> if is_dir if mesg.archive != 'tar.bz2' cb("The only supported directory archive format is tar.bz2") return target = temp.path(suffix:'.' + mesg.archive) #dbg("'#{path}' is a directory, so archive it to '#{target}', change path, and read that file") archive = mesg.archive if path[path.length-1] == '/' # common nuisance with paths to directories path = path.slice(0,path.length-1) split = misc.path_split(path) path = target # same patterns also in project.coffee (TODO) args = ["--exclude=.sagemathcloud*", '--exclude=.forever', '--exclude=.node*', '--exclude=.npm', '--exclude=.sage', '-jcf', target, split.tail] #dbg("tar #{args.join(' ')}") child_process.execFile 'tar', args, {cwd:split.head}, (err, stdout, stderr) -> if err winston.debug("Issue creating tarball: #{err}, #{stdout}, #{stderr}") cb(err) else cb() else #dbg("It is a file.") cb() (cb) -> #dbg("Read the file into memory.") fs.readFile path, (err, _data) -> data = _data cb(err) (cb) -> id = misc_node.uuidsha1(data) #dbg("sha1 hash = '#{id}'") cb() (cb) -> #dbg("send the file as a blob back to the hub.") socket.write_mesg 'json', message.file_read_from_project(id:mesg.id, data_uuid:id, archive:archive) socket.write_mesg 'blob', {uuid:id, blob:data, ttlSeconds:mesg.ttlSeconds} cb() ], (err) -> if err and err != 'file already known' socket.write_mesg('json', message.error(id:mesg.id, error:err)) if is_dir fs.exists path, (exists) -> if exists #dbg("It was a directory, so remove the temporary archive '#{path}'.") fs.unlink(path) ) exports.write_file_to_project = (socket, mesg) -> #dbg = (m) -> winston.debug("write_file_to_project(path='#{mesg.path}'): #{m}") #dbg() data_uuid = mesg.data_uuid path = misc_node.abspath(mesg.path) # Listen for the blob containing the actual content that we will write. write_file = (type, value) -> if type == 'blob' and value.uuid == data_uuid socket.removeListener('mesg', write_file) try await ensureContainingDirectoryExists(path) await writeFile(path, value.blob) socket.write_mesg 'json', message.file_written_to_project(id:mesg.id) catch err socket.write_mesg 'json', message.error(id:mesg.id, error:err) socket.on('mesg', write_file)