Как загрузить частичный поток на Google Drive с помощью Node.JS - PullRequest
0 голосов
/ 28 октября 2018

Я хочу добиться функциональности, когда я могу загрузить определенную часть файла на Google Drive.Я могу сделать это, разделив исходный поток чтения на несколько потоков записи, а затем загрузив их, но этот метод неприемлем, поскольку потоки записи будут жить на сервере (что мне не нужно).

Я пытался преодолеть это, отправляя исходный поток чтения в теле запроса на загрузку, но я не могу найти способ остановить загрузку при выполнении определенного условия.Моя функция загрузки выглядит следующим образом:

var upload = (auth, google, fileName, readStream, res, lastChunk) => {

console.log(`uploading ${fileName}`);

const drive = google.drive({ version: 'v3', auth });

var fileMetadata = {
    'name': fileName
};

var media = {
    mimeType: 'application/octet-stream',
    body: readStream
};

drive.files.create({
    resource: fileMetadata,
    media: media,
    fields: 'id',
    headers: {
        'uploadType': 'multipart'
    }
}, {
    onUploadProgress: function (e) {
        if (e.bytesRead > 786432){
            // want to stop uploading
            //readStream.close() <- this doesn't stop the upload
        }

        console.log(`Uploaded ${fileName}:`, e.bytesRead.toString());
    }
}, function (err, file) {
    if (err) {
        console.error(err);
    } else {

        if (lastChunk)
            res.render('upload-success.hbs');

        console.log('File Id: ', file.id);
    }
});

Можно ли как-нибудь остановить загрузку и сохранить загруженную часть в Google Диске без изменений?Я пробовал несколько действий в потоке, включая закрытие, приостановку, но ни одно из них не останавливает загрузку.Что-то, что я хотел бы добавить, это то, что если я прочитал X байтов потока и загрузил его, то были загружены правильные байты, то есть байты от X в палатах.

1 Ответ

0 голосов
/ 29 октября 2018

На основе этого блога вы можете добавить обработчик для полученного фрагмента тела части запроса.Примерно так:

function write_chunk(request, fileDescriptor, chunk, isLast, closePromise) {
    // Pause receiving request data (until current chunk is written)
    request.pause();
    // Write chunk to file
    sys.debug("Writing chunk");
    posix.write(fileDescriptor, chunk).addCallback(function() {
        sys.debug("Wrote chunk");
        // Resume receiving request data
        request.resume();
        // Close file if completed
        if (isLast) {
            sys.debug("Closing file");
            posix.close(fileDescriptor).addCallback(function() {
                sys.debug("Closed file");

                // Emit file close promise
                closePromise.emitSuccess();
            });
        }
    });
}

function upload_file(req, res) {
     // Request body is binary
     req.setBodyEncoding("binary");


// Handle request as multipart
var stream = new multipart.Stream(req);

// Create promise that will be used to emit event on file close
var closePromise = new events.Promise();

// Add handler for a request part received
stream.addListener("part", function(part) {
    sys.debug("Received part, name = " + part.name + ", filename = " + part.filename);

    var openPromise = null;

    // Add handler for a request part body chunk received
    part.addListener("body", function(chunk) {
        // Calculate upload progress
        var progress = (stream.bytesReceived / stream.bytesTotal * 100).toFixed(2);
        var mb = (stream.bytesTotal / 1024 / 1024).toFixed(1);

        sys.debug("Uploading " + mb + "mb (" + progress + "%)");

        // Ask to open/create file (if not asked before)
        if (openPromise == null) {
            sys.debug("Opening file");
            openPromise = posix.open("./uploads/" + part.filename, process.O_CREAT | process.O_WRONLY, 0600);
        }

        // Add callback to execute after file is opened
        // If file is already open it is executed immediately
        openPromise.addCallback(function(fileDescriptor) {
            // Write chunk to file
            write_chunk(req, fileDescriptor, chunk, 
                (stream.bytesReceived == stream.bytesTotal), closePromise);
        });
    });
});

Все вызовы ввода / вывода являются асинхронными, поэтому метод записи выполняется не сразу.Поэтому используйте addCallback метод events.Promise для обработки вызовов метода и использования для уведомления.В нем говорится, что для обеспечения надежного функционирования необходимы request.resume() и request.pause(), чтобы избежать повреждения файлов.

...