1
0
mirror of https://github.com/demodude4u/Factorio-FBSR.git synced 2024-11-24 08:12:21 +02:00

Re-did the blueprint string finding

This commit is contained in:
Weston Rye (Demod) 2017-06-06 23:20:13 -04:00
parent 553135a509
commit 01ae8b9a61
3 changed files with 174 additions and 127 deletions

View File

@ -0,0 +1,117 @@
package com.demod.fbsr;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.JSONObject;
import com.demod.factorio.Utils;
public final class BlueprintFinder {
public enum Provider {
PASTEBIN("pastebin\\.com/(?<id>[A-Za-z0-9]+)", m -> "https://pastebin.com/raw/" + m.group("id")), //
HASTEBIN("hastebin\\.com/(?<id>[A-Za-z0-9]+)", m -> "https://hastebin.com/raw/" + m.group("id")), //
GITLAB("gitlab\\.com/snippets/(?<id>[A-Za-z0-9]+)",
m -> "https://gitlab.com/snippets/" + m.group("id") + "/raw"), //
GIST("gist\\.github\\.com/[-a-zA-Z0-9]+/(?<id>[a-z0-9]+)", (m, l) -> {
JSONObject response = WebUtils.readJsonFromURL("https://api.github.com/gists/" + m.group("id"));
JSONObject filesJson = response.getJSONObject("files");
Utils.<JSONObject>forEach(filesJson, (k, v) -> {
if (v.getString("type").equals("text/plain")) {
l.addURL(v.getString("raw_url"));
}
});
}), //
TEXT_URLS("\\b(?<url>(?:https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|])", (m, l) -> {
URL url = new URL(m.group("url"));
URLConnection connection = url.openConnection();
if (connection.getContentType().startsWith("text/plain")) {
l.addURL(m.group("url"));
}
}), //
;
@FunctionalInterface
private interface Listener {
void addURL(String url) throws Exception;
}
@FunctionalInterface
private interface Mapper {
void matched(Matcher matcher, Listener listener) throws Exception;
}
private Pattern pattern;
private final Mapper mapper;
private Provider(String regex, Function<Matcher, String> simpleMapper) {
this(regex, (m, l) -> l.addURL(simpleMapper.apply(m)));
}
private Provider(String regex, Mapper mapper) {
this.mapper = mapper;
pattern = Pattern.compile(regex);
}
}
private static final Pattern blueprintPattern = Pattern.compile("([0-9][A-Za-z0-9+\\/=\\r\\n]{90,})");
private static void findBlueprints(InputStream in, BlueprintReporting reporting,
List<BlueprintStringData> results) {
try (Scanner scanner = new Scanner(in)) {
String blueprintString;
while ((blueprintString = scanner.findWithinHorizon(blueprintPattern, 4000000)) != null) {
try {
reporting.addContext(blueprintString);
results.add(new BlueprintStringData(blueprintString));
} catch (Exception e) {
reporting.addException(e);
}
}
}
}
private static void findProviders(String content, BlueprintReporting reporting, List<BlueprintStringData> results) {
int initialResultCount = results.size();
for (Provider provider : Provider.values()) {
Matcher matcher = provider.pattern.matcher(content);
if (matcher.find()) {
try {
provider.mapper.matched(matcher, in -> {
findBlueprints(new URL(in).openStream(), reporting, results);
});
} catch (Exception e) {
reporting.addException(e);
}
}
if (results.size() != initialResultCount) {
reporting.addContext(content);
break;
}
}
}
public static List<BlueprintStringData> search(String content, BlueprintReporting reporting) {
List<BlueprintStringData> results = new ArrayList<>();
findBlueprints(new ByteArrayInputStream(content.getBytes()), reporting, results);
findProviders(content, reporting, results);
return results;
}
private BlueprintFinder() {
}
}

View File

@ -2,6 +2,13 @@ package com.demod.fbsr;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import org.json.JSONException;
import org.json.JSONObject;
import com.demod.factorio.Utils;
public final class WebUtils {
public static InputStream limitMaxBytes(InputStream delegate, int maxBytes) {
@ -31,6 +38,10 @@ public final class WebUtils {
};
}
public static JSONObject readJsonFromURL(String url) throws JSONException, MalformedURLException, IOException {
return Utils.readJsonFromStream(new URL(url).openStream());
}
private WebUtils() {
}
}

View File

@ -2,16 +2,12 @@ package com.demod.fbsr.app;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLConnection;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@ -28,11 +24,11 @@ import com.demod.dcba.CommandHandler;
import com.demod.dcba.DCBA;
import com.demod.dcba.DiscordBot;
import com.demod.fbsr.Blueprint;
import com.demod.fbsr.BlueprintFinder;
import com.demod.fbsr.BlueprintReporting;
import com.demod.fbsr.BlueprintStringData;
import com.demod.fbsr.FBSR;
import com.demod.fbsr.RenderUtils;
import com.demod.fbsr.WebUtils;
import com.demod.fbsr.WorldMap;
import com.demod.fbsr.WorldMap.Debug;
import com.google.common.collect.LinkedHashMultiset;
@ -42,7 +38,6 @@ import com.google.common.util.concurrent.AbstractIdleService;
import net.dv8tion.jda.core.EmbedBuilder;
import net.dv8tion.jda.core.entities.Message;
import net.dv8tion.jda.core.entities.Message.Attachment;
import net.dv8tion.jda.core.entities.MessageEmbed;
import net.dv8tion.jda.core.entities.PrivateChannel;
import net.dv8tion.jda.core.events.message.MessageReceivedEvent;
@ -51,92 +46,14 @@ public class BlueprintBotDiscordService extends AbstractIdleService {
private static final String USERID_DEMOD = "100075603016814592";
private static final int BP_MAX_SIZE = 4000000;
private static final Pattern blueprintPattern = Pattern.compile("([0-9][A-Za-z0-9+\\/=\\r\\n]{90,})");
private static final Pattern debugPattern = Pattern.compile("DEBUG:([A-Za-z0-9_]+)");
private static final Pattern pastebinPattern = Pattern.compile("pastebin\\.com/([A-Za-z0-9]+)");
private static final Pattern hastebinPattern = Pattern.compile("hastebin\\.com/([A-Za-z0-9]+)");
private static final Pattern gistPattern = Pattern.compile("gist\\.github\\.com/([-a-zA-Z0-9@:%_\\+.~#?&//=]+)");
private static final Pattern gitlabSnippetPattern = Pattern.compile("gitlab\\.com/snippets/([A-Za-z0-9]+)");
public static void main(String[] args) {
new BlueprintBotDiscordService().startAsync();
}
private DiscordBot bot;
private void findBlueprints(MessageReceivedEvent event, BlueprintReporting reporting, String content) {
Matcher matcher = blueprintPattern.matcher(content);
while (matcher.find()) {
String blueprintString = matcher.group();
reporting.addContext(blueprintString);
try {
event.getChannel().sendTyping().complete();
BlueprintStringData blueprintStringData = new BlueprintStringData(blueprintString);
System.out.println("Parsing blueprints: " + blueprintStringData.getBlueprints().size());
if (blueprintStringData.getBlueprints().size() == 1) {
BufferedImage image = FBSR.renderBlueprint(blueprintStringData.getBlueprints().get(0), reporting);
byte[] imageData = generateDiscordFriendlyPNGImage(image);
Message message = event.getChannel()
.sendFile(new ByteArrayInputStream(imageData), "blueprint.png", null).complete();
reporting.addImageURL(message.getAttachments().get(0).getUrl());
} else {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos)) {
int counter = 1;
for (Blueprint blueprint : blueprintStringData.getBlueprints()) {
try {
BufferedImage image = FBSR.renderBlueprint(blueprint, reporting);
zos.putNextEntry(new ZipEntry("blueprint " + counter + ".png"));
ImageIO.write(image, "PNG", zos);
} catch (Exception e) {
reporting.addException(e);
}
counter++;
}
zos.close();
byte[] zipData = baos.toByteArray();
Message message = event.getChannel()
.sendFile(new ByteArrayInputStream(zipData), "blueprint book images.zip", null)
.complete();
reporting.addDownloadURL(message.getAttachments().get(0).getUrl());
}
}
} catch (Exception e) {
reporting.addException(e);
}
}
}
private void findBlueprintsInURL(MessageReceivedEvent event, BlueprintReporting reporting, String url) {
StringBuilder contentBuilder = new StringBuilder();
reporting.addContext(url);
try {
URLConnection hc = new URL(url).openConnection();
hc.setRequestProperty("User-Agent",
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2");
try (BufferedReader br = new BufferedReader(
new InputStreamReader(WebUtils.limitMaxBytes(hc.getInputStream(), BP_MAX_SIZE)))) {
String line;
while ((line = br.readLine()) != null) {
contentBuilder.append(line).append('\n');
}
findBlueprints(event, reporting, contentBuilder.toString());
}
} catch (IOException e) {
reporting.addException(e);
}
}
private void findDebugOptions(BlueprintReporting reporting, String content) {
Matcher matcher = debugPattern.matcher(content);
while (matcher.find()) {
@ -156,45 +73,6 @@ public class BlueprintBotDiscordService extends AbstractIdleService {
}
}
private void findTextAttachments(MessageReceivedEvent event, BlueprintReporting reporting) {
for (Attachment attachment : event.getMessage().getAttachments()) {
if (attachment.getSize() < BP_MAX_SIZE) {
findBlueprintsInURL(event, reporting, attachment.getUrl());
}
}
}
private void findTextHostingSites(MessageReceivedEvent event, BlueprintReporting reporting, String content) {
{
Matcher matcher = pastebinPattern.matcher(content);
while (matcher.find()) {
String code = matcher.group(1);
findBlueprintsInURL(event, reporting, "https://pastebin.com/raw/" + code);
}
}
{
Matcher matcher = hastebinPattern.matcher(content);
while (matcher.find()) {
String code = matcher.group(1);
findBlueprintsInURL(event, reporting, "https://hastebin.com/raw/" + code);
}
}
{
Matcher matcher = gitlabSnippetPattern.matcher(content);
while (matcher.find()) {
String code = matcher.group(1);
findBlueprintsInURL(event, reporting, "https://gitlab.com/snippets/" + code + "/raw");
}
}
{
Matcher matcher = gistPattern.matcher(content);
while (matcher.find()) {
String code = matcher.group(1);
findBlueprintsInURL(event, reporting, "https://gist.githubusercontent.com/" + code + "/raw/");
}
}
}
private byte[] generateDiscordFriendlyPNGImage(BufferedImage image) throws IOException {
byte[] imageData;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
@ -217,6 +95,49 @@ public class BlueprintBotDiscordService extends AbstractIdleService {
}
}
private void processBlueprints(List<BlueprintStringData> blueprintStrings, MessageReceivedEvent event,
BlueprintReporting reporting, String content) {
for (BlueprintStringData blueprintString : blueprintStrings) {
try {
event.getChannel().sendTyping().complete();
System.out.println("Parsing blueprints: " + blueprintString.getBlueprints().size());
if (blueprintString.getBlueprints().size() == 1) {
BufferedImage image = FBSR.renderBlueprint(blueprintString.getBlueprints().get(0), reporting);
byte[] imageData = generateDiscordFriendlyPNGImage(image);
Message message = event.getChannel()
.sendFile(new ByteArrayInputStream(imageData), "blueprint.png", null).complete();
reporting.addImageURL(message.getAttachments().get(0).getUrl());
} else {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos)) {
int counter = 1;
for (Blueprint blueprint : blueprintString.getBlueprints()) {
try {
BufferedImage image = FBSR.renderBlueprint(blueprint, reporting);
zos.putNextEntry(new ZipEntry("blueprint " + counter + ".png"));
ImageIO.write(image, "PNG", zos);
} catch (Exception e) {
reporting.addException(e);
}
counter++;
}
zos.close();
byte[] zipData = baos.toByteArray();
Message message = event.getChannel()
.sendFile(new ByteArrayInputStream(zipData), "blueprint book images.zip", null)
.complete();
reporting.addDownloadURL(message.getAttachments().get(0).getUrl());
}
}
} catch (Exception e) {
reporting.addException(e);
}
}
}
private void sendReportToDemod(MessageReceivedEvent event, BlueprintReporting reporting) {
Optional<Debug> debug = reporting.getDebug();
List<String> contexts = reporting.getContexts();
@ -325,13 +246,11 @@ public class BlueprintBotDiscordService extends AbstractIdleService {
BlueprintReporting reporting = new BlueprintReporting();
System.out.println("\n############################################################\n");
findDebugOptions(reporting, content);
findBlueprints(event, reporting, content);
findTextHostingSites(event, reporting, content);
findTextAttachments(event, reporting);
processBlueprints(BlueprintFinder.search(content, reporting), event, reporting, content);
sendReportToDemod(event, reporting);
})//
.withHelp("Renders an image of the blueprint string provided. Longer blueprints "
+ "can be attached as files or linked with pastebin, hastebin, or gist URLs.")//
+ "can be attached as files or linked with pastebin, hastebin, gitlab, or gist URLs.")//
//
.create();