Fixed up multipart stuff, added proper js.

This commit is contained in:
Andrew Lalis 2023-07-16 12:27:22 -04:00
parent 401859fa74
commit df8a6dd192
6 changed files with 57 additions and 11 deletions

1
.gitignore vendored
View File

@ -15,3 +15,4 @@ create-schematic-gen-site-test-*
*.obj *.obj
*.lst *.lst
*.jar *.jar
extracts/

View File

@ -4,7 +4,7 @@
], ],
"copyright": "Copyright © 2023, Andrew Lalis", "copyright": "Copyright © 2023, Andrew Lalis",
"dependencies": { "dependencies": {
"handy-httpd": "~>7.6.1", "handy-httpd": "~>7.6.3",
"slf4d": "~>2.4.1" "slf4d": "~>2.4.1"
}, },
"description": "HTTP server for generating schematic materials lists.", "description": "HTTP server for generating schematic materials lists.",

View File

@ -1,7 +1,7 @@
{ {
"fileVersion": 1, "fileVersion": 1,
"versions": { "versions": {
"handy-httpd": "7.6.1", "handy-httpd": "7.6.3",
"httparsed": "1.2.1", "httparsed": "1.2.1",
"slf4d": "2.4.1", "slf4d": "2.4.1",
"streams": "3.5.0" "streams": "3.5.0"

View File

@ -1,6 +1,8 @@
const form = document.getElementById("schematic-form"); const form = document.getElementById("schematic-form");
const resultContainer = document.getElementById("result-container");
form.onsubmit = async (e) => { form.onsubmit = async (e) => {
e.preventDefault(); e.preventDefault();
resultContainer.innerHTML = "";
console.log(e); console.log(e);
const data = new FormData(form); const data = new FormData(form);
console.log(data); console.log(data);
@ -10,9 +12,12 @@ form.onsubmit = async (e) => {
body: data body: data
}); });
const result = await response.json(); const result = await response.json();
console.log("Success:", result); const extractId = result.extractId;
const url = window.location.origin + "/extracts/" + extractId;
resultContainer.innerHTML = `<p>Copy this URL, and provide it to the computer: <em>${url}</em></p>`;
form.reset(); form.reset();
} catch (error) { } catch (error) {
console.error("Error: " + error); console.error("Error: " + error);
resultContainer.innerHTML = `<p>An error occurred: ${error}</p>`;
} }
}; };

View File

@ -14,6 +14,9 @@
<input id="schematic-file-input" name="schematics" type="file" multiple accept=".nbt" required/> <input id="schematic-file-input" name="schematics" type="file" multiple accept=".nbt" required/>
<button type="submit">Submit</button> <button type="submit">Submit</button>
</form> </form>
<div id="result-container">
</div>
<script src="files.js"></script> <script src="files.js"></script>
</body> </body>

View File

@ -3,6 +3,12 @@ import handy_httpd.handlers.path_delegating_handler;
import handy_httpd.handlers.file_resolving_handler; import handy_httpd.handlers.file_resolving_handler;
import slf4d; import slf4d;
import slf4d.default_provider; 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() { void main() {
auto provider = new shared DefaultProvider(true, Levels.INFO); auto provider = new shared DefaultProvider(true, Levels.INFO);
@ -15,7 +21,7 @@ void main() {
PathDelegatingHandler handler = new PathDelegatingHandler(); PathDelegatingHandler handler = new PathDelegatingHandler();
handler.addMapping("POST", "/extracts", &handleExtract); handler.addMapping("POST", "/extracts", &handleExtract);
handler.addMapping("GET", "/extracts/{extractId:uint}", &getExtract); handler.addMapping("GET", "/extracts/{extractId}", &getExtract);
FileResolvingHandler fileHandler = new FileResolvingHandler("site", DirectoryResolutionStrategies.serveIndexFiles); FileResolvingHandler fileHandler = new FileResolvingHandler("site", DirectoryResolutionStrategies.serveIndexFiles);
handler.addMapping("/**", fileHandler); handler.addMapping("/**", fileHandler);
@ -23,15 +29,46 @@ void main() {
} }
void handleExtract(ref HttpRequestContext ctx) { void handleExtract(ref HttpRequestContext ctx) {
MultipartFormData data = ctx.request.readBodyAsMultipartFormData();
infoF!"Read %d files: "(data.elements.length);
import std.json; 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; JSONValue result = JSONValue.emptyObject;
result.object["extractId"] = JSONValue(42); result.object["extractId"] = JSONValue(extractId.toString());
ctx.response.writeBodyString(result.toJSON(), "application/json"); 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) { void getExtract(ref HttpRequestContext ctx) {
infoF!"Getting extract: %d"(ctx.request.getPathParamAs!uint("extractId")); string extractId = ctx.request.getPathParamAs!string("extractId");
const extractFile = buildPath(EXTRACTS_DIR, extractId, EXTRACT_FILENAME);
fileResponse(ctx.response, extractFile, "application/json");
} }