import handy_httpd; import handy_httpd.handlers.path_delegating_handler; import handy_httpd.handlers.file_resolving_handler; import slf4d; import slf4d.default_provider; import std.path; import std.file; const EXTRACTS_DIR = "extracts"; const EXTRACT_FILENAME = "__EXTRACT__.json"; const EXTRACT_COMMAND = ["java", "-jar", "materials-extractor-v1.0.0.jar"]; void main() { auto provider = new shared DefaultProvider(true, Levels.INFO); configureLoggingProvider(provider); ServerConfig config = ServerConfig.defaultValues(); config.workerPoolSize = 3; config.connectionQueueSize = 10; config.port = 8100; PathDelegatingHandler handler = new PathDelegatingHandler(); handler.addMapping("POST", "/extracts", &handleExtract); handler.addMapping("GET", "/extracts/{extractId}", &getExtract); FileResolvingHandler fileHandler = new FileResolvingHandler("site", DirectoryResolutionStrategies.serveIndexFiles); handler.addMapping("/**", fileHandler); new HttpServer(handler, config).start(); } void handleExtract(ref HttpRequestContext ctx) { import std.json; import std.uuid; import std.process; import std.stdio; immutable UUID extractId = randomUUID(); MultipartFormData data = ctx.request.readBodyAsMultipartFormData(); // TODO: Validate data (unique filenames, no non-file elements, etc.) const extractDir = buildPath(EXTRACTS_DIR, extractId.toString()); if (!exists(extractDir)) { mkdirRecurse(extractDir); } string[] filenames; foreach (MultipartElement element; data.elements) { if (element.filename.isNull) continue; const filePath = buildPath(extractDir, element.filename.get()); std.file.write(filePath, element.content); filenames ~= filePath; } const extractJsonPath = buildPath(extractDir, EXTRACT_FILENAME); infoF!"Running extract process on files: %s"(filenames); Pid pid = spawnProcess(EXTRACT_COMMAND ~ filenames, std.stdio.stdin, File(extractJsonPath, "w")); int exitCode = wait(pid); infoF!"Exit code: %d"(exitCode); if (exitCode != 0) { ctx.response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR); ctx.response.writeBodyString(readText(extractJsonPath)); } else { JSONValue result = JSONValue.emptyObject; result.object["extractId"] = JSONValue(extractId.toString()); ctx.response.writeBodyString(result.toJSON(), "application/json"); // Remove schematic files after we are done. foreach (string schematicFile; filenames) { std.file.remove(schematicFile); } } } void getExtract(ref HttpRequestContext ctx) { string extractId = ctx.request.getPathParamAs!string("extractId"); const extractFile = buildPath(EXTRACTS_DIR, extractId, EXTRACT_FILENAME); fileResponse(ctx.response, extractFile, "application/json"); }