WIP: Support for streaming multipart form data to the file system
This commit is contained in:
parent
59b425fd5c
commit
8edefffbc5
|
@ -34,14 +34,19 @@ exports.startup = function() {
|
||||||
logger.alert("The plugin 'tiddlywiki/multiwikiserver' requires the better-sqlite3 npm package to be installed. Run 'npm install' in the root of the TiddlyWiki repository");
|
logger.alert("The plugin 'tiddlywiki/multiwikiserver' requires the better-sqlite3 npm package to be installed. Run 'npm install' in the root of the TiddlyWiki repository");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Compute the database path
|
// Create and initialise the tiddler store and upload manager
|
||||||
var databasePath = path.resolve($tw.boot.wikiPath,"store/database.sqlite");
|
var SqlTiddlerStore = require("$:/plugins/tiddlywiki/multiwikiserver/sql-tiddler-store.js").SqlTiddlerStore,
|
||||||
// Create and initialise the tiddler store
|
store = new SqlTiddlerStore({
|
||||||
var SqlTiddlerStore = require("$:/plugins/tiddlywiki/multiwikiserver/sql-tiddler-store.js").SqlTiddlerStore;
|
databasePath: path.resolve($tw.boot.wikiPath,"store/database.sqlite")
|
||||||
|
}),
|
||||||
|
UploadManager = require("$:/plugins/tiddlywiki/multiwikiserver/upload-manager.js").UploadManager,
|
||||||
|
uploadManager = new UploadManager({
|
||||||
|
inboxPath: path.resolve($tw.boot.wikiPath,"store/inbox"),
|
||||||
|
store: store
|
||||||
|
});
|
||||||
$tw.mws = {
|
$tw.mws = {
|
||||||
store: new SqlTiddlerStore({
|
store: store,
|
||||||
databasePath: databasePath
|
uploadManager: uploadManager
|
||||||
})
|
|
||||||
};
|
};
|
||||||
// Create docs bag and recipe
|
// Create docs bag and recipe
|
||||||
$tw.mws.store.createBag("docs","TiddlyWiki Documentation from https://tiddlywiki.com/");
|
$tw.mws.store.createBag("docs","TiddlyWiki Documentation from https://tiddlywiki.com/");
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*\
|
||||||
|
title: $:/plugins/tiddlywiki/multiwikiserver/upload-manager.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: library
|
||||||
|
|
||||||
|
A class that handles an incoming multipart/form-data stream, streaming the data to temporary files
|
||||||
|
in the store/inbox folder. It invokes a callback when all the data is available. The callback can explicitly
|
||||||
|
claim some or all of the files, otherwise they are deleted on return from the callback. Claimed files should
|
||||||
|
be moved out of the store/inbox folder.
|
||||||
|
|
||||||
|
\*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create an instance of the upload manager. Options include:
|
||||||
|
|
||||||
|
inboxPath - path to the inbox folder
|
||||||
|
store - sqlTiddlerStore to use for saving tiddlers
|
||||||
|
*/
|
||||||
|
function UploadManager(options) {
|
||||||
|
const path = require("path");
|
||||||
|
options = options || {};
|
||||||
|
this.inboxPath = path.resolve(options.inboxPath,);
|
||||||
|
this.store = options.store;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Process a new multipart/form-data stream. Options include:
|
||||||
|
|
||||||
|
state - provided by server.js
|
||||||
|
recipe - optional name of recipe to write to (one of recipe or bag must be specified)
|
||||||
|
bag - optional name of bag to write to (one of recipe or bag must be specified)
|
||||||
|
callback - invoked as callback(err,results). Results is an array of {title:,bag_name:}
|
||||||
|
|
||||||
|
formData is:
|
||||||
|
{
|
||||||
|
parts: [
|
||||||
|
{
|
||||||
|
name: "fieldname",
|
||||||
|
filename: "filename",
|
||||||
|
filePath: "/users/home/mywiki/store/inbox/09cabc74-8163-4ead-a35b-4ca768f02d62/64131628-cbff-4677-b146-d85c42c232dc",
|
||||||
|
headers: {
|
||||||
|
name: "value",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
UploadManager.prototype.processNewStream = function(options) {
|
||||||
|
let fileStream = null;
|
||||||
|
let fieldValue = "";
|
||||||
|
state.streamMultipartData({
|
||||||
|
cbPartStart: function(headers,name,filename) {
|
||||||
|
console.log(`Received file ${name} and ${filename} with ${JSON.stringify(headers)}`)
|
||||||
|
if(filename) {
|
||||||
|
fileStream = fs.createWriteStream(filename);
|
||||||
|
} else {
|
||||||
|
fieldValue = "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cbPartChunk: function(chunk) {
|
||||||
|
if(fileStream) {
|
||||||
|
fileStream.write(chunk);
|
||||||
|
} else {
|
||||||
|
fieldValue = fieldValue + chunk;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cbPartEnd: function() {
|
||||||
|
if(fileStream) {
|
||||||
|
fileStream.end();
|
||||||
|
fileStream = null;
|
||||||
|
} else {
|
||||||
|
console.log("Data was " + fieldValue);
|
||||||
|
fieldValue = "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cbFinished: function(err) {
|
||||||
|
if(err) {
|
||||||
|
state.sendResponse(400,{"Content-Type": "text/plain"},"Bad Request: " + err);
|
||||||
|
} else {
|
||||||
|
state.sendResponse(200, {"Content-Type": "text/plain"},"Multipart data processed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
UploadManager.prototype.close = function() {
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.UploadManager = UploadManager;
|
||||||
|
|
||||||
|
})();
|
Loading…
Reference in New Issue