demodude4u / Factorio-FBSR

Factorio Blueprint String Renderer
MIT License
74 stars 20 forks source link

Add an option to the webapi for local storage of images #115

Closed tzwaan closed 4 years ago

tzwaan commented 5 years ago

Currently the webapi simply accepts string, which it will convert into an image and upload to discord or mixtape.moe

I request an option to have the webapi save the file to a local directory specified in the the config, without uploading it to a remote host. It should then answer the original request with the filename (+ maybe the total path).

If an extra image_host_url (or whatever you want to call it) is set in the config, you could even have it: <image_host_url>/<filename> instead. So the user running the bot can specify the host on which the save folder is being hosted, and get the direct url back from the bot.

tzwaan commented 5 years ago

Following our discussion on discord:

The filename should probably be something in the format of: <timestamp>-<blueprint-name>-<possible_random_string>

Also, extra logging in the returned json file would be useful. (even when not using the local save)

maybe even this and other (probably not) useful stuff.

tzwaan commented 5 years ago

Instead of only having the filename being (randomly) generated, have an option to supply the api with a filename beforehand.

DanielNagy commented 5 years ago

Here's a crude way. Add the following On post listening on the /blueprintlocal URI into the WebAPIService.java file. Update it with the appropriate folder / path details you require. As for the json response on the post, you can adjust the response on the image.put("url", pair.getValue()); to suit your needs (imagehost url from config etc). The discord service code was also removed from this.

        On.post("/blueprintlocal").serve((req, resp) -> {
            TaskReporting reporting = new TaskReporting();
            try {
                String content = Optional.ofNullable(req.body()).map(String::new).orElse("");
                reporting.setContext(content);

                List<BlueprintStringData> blueprintStrings = BlueprintFinder.search(content, reporting);
                List<Blueprint> blueprints = blueprintStrings.stream().flatMap(s -> s.getBlueprints().stream()).collect(Collectors.toList());

                for (Blueprint blueprint : blueprints) {
                    try {
                        BufferedImage image = FBSR.renderBlueprint(blueprint, reporting);
                        String fileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + "-"
                                + Integer.toString(new Random().nextInt(1000000000)) + ".png";
                        File outputfile = new File(fileName);
                        if (outputfile.exists())
                            throw new IOException("FileExists");
                        ImageIO.write(image, "png", outputfile);
                        reporting.addImage(blueprint.getLabel(), fileName);

                    } catch (Exception e) {
                        reporting.addException(e);
                    }
                }
            } catch (Exception e) {
                reporting.addException(e);
            }

            JSONObject result = new JSONObject();
            Utils.terribleHackToHaveOrderedJSONObject(result);

            if (!reporting.getExceptions().isEmpty()) {
                reporting.addInfo(
                        "There was a problem completing your request. I have contacted my programmer to fix it for you!");
            }

            if (!reporting.getInfo().isEmpty()) {
                result.put("info", new JSONArray(reporting.getInfo()));
            }

            if (!reporting.getImages().isEmpty()) {
                JSONArray images = new JSONArray();
                for (Entry<Optional<String>, String> pair : reporting.getImages()) {
                    JSONObject image = new JSONObject();
                    Utils.terribleHackToHaveOrderedJSONObject(image);
                    pair.getKey().ifPresent(l -> image.put("label", l));
                    image.put("url", pair.getValue());
                    images.put(image);
                }
                result.put("images", images);
            }

            resp.contentType(MediaType.JSON);
            resp.body(result.toString(2).getBytes());

            return resp;
        });
demodude4u commented 4 years ago

The lines added in this commit shows the solution I went with: https://github.com/demodude4u/Factorio-FBSR/commit/df2f069d76907e22addcbf1c97f278abb00ca36d#diff-7ced1c7cccb0608fcf087a15cd0ac9aeR33-R49

I decided to keep it simple for now, the filename is formatted Blueprint<id>.png, where id is System.currentTimeMillis() or a number close to it, which is unique.

Please open up a new issue if a more sophisticated file naming scheme is needed. 🙂