Gymboard/gymboard-uploads/source/handlers.d

76 lines
2.5 KiB
D

module handlers;
import handy_httpd;
import slf4d;
import std.conv : to;
import std.path;
import std.file;
import std.uuid;
import std.json;
import std.stdio;
static immutable MAX_UPLOAD_SIZE = 1024 * 1024 * 1024;
static immutable ALLOWED_MEDIA_TYPES = ["video/mp4"];
static immutable TEMP_UPLOADS_DIR = "temp-uploads";
class VideoUploadHandler : HttpRequestHandler {
public void handle(ref HttpRequestContext ctx) {
if (!validateHeaders(ctx)) return;
if (!exists(TEMP_UPLOADS_DIR)) mkdir(TEMP_UPLOADS_DIR);
UUID uploadId = sha1UUID("gymboard-uploads");
ctx.request.readBodyToFile(getTempFilePath(uploadId));
JSONValue metadataObj = JSONValue(string[string].init); // Empty object.
string originalFilename = ctx.request.getHeader("X-GYMBOARD-FILENAME");
if (originalFilename is null) {
originalFilename = "unnamed.mp4";
}
metadataObj.object["filename"] = originalFilename;
File f = File(getTempFileMetadataPath(uploadId), "w");
f.write(metadataObj.toPrettyString());
f.close();
infoF!"Saved uploaded video file with id %s."(uploadId.toString);
ctx.response.setStatus(HttpStatus.CREATED);
ctx.response.writeBodyString(uploadId.toString());
}
private bool validateHeaders(ref HttpRequestContext ctx) {
ulong contentLength = ctx.request.getHeaderAs!ulong("Content-Length");
if (contentLength == 0) {
ctx.response.status = HttpStatus.LENGTH_REQUIRED;
return false;
} else if (contentLength > MAX_UPLOAD_SIZE) {
ctx.response.status = HttpStatus.PAYLOAD_TOO_LARGE;
return false;
}
import std.algorithm : canFind;
string contentType = ctx.request.getHeader("Content-Type");
if (contentType is null || !canFind(ALLOWED_MEDIA_TYPES, contentType)) {
ctx.response.status = HttpStatus.UNSUPPORTED_MEDIA_TYPE;
return false;
}
return true;
}
private string getTempFilePath(const ref UUID uploadId) {
return buildPath(TEMP_UPLOADS_DIR, uploadId.toString());
}
private string getTempFileMetadataPath(const ref UUID uploadId) {
return buildPath(TEMP_UPLOADS_DIR, uploadId.toString() ~ "_meta.json");
}
}
class VideoProcessingHandler : HttpRequestHandler {
public void handle(ref HttpRequestContext ctx) {
string uploadIdStr = ctx.request.getPathParamAs!string("uploadId");
infoF!"Processing upload %s"(uploadIdStr);
}
}