added framework for auto resource fetching for the apps

This commit is contained in:
gnembon committed 2021-05-21 22:31:02 -03:00
1 parent 79fb489ab7
commit dbae5813f0
5 files changed
+91 -75

No files matched your search

@@ -271,13 +271,13 @@ public class ScriptCommand
suggests( (cc, bb) -> suggestMatching(CarpetServer.scriptServer.listAvailableModules(true),bb)).
executes((cc) ->
{
boolean success = CarpetServer.scriptServer.addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, true, false, false);
boolean success = CarpetServer.scriptServer.addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, true, false, false, null);
return success?1:0;
}).
then(literal("global").
executes((cc) ->
{
boolean success = CarpetServer.scriptServer.addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, false, false, false);
boolean success = CarpetServer.scriptServer.addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, false, false, false, null);
return success?1:0;
}
)
@@ -328,8 +328,9 @@ public class ScriptCommand
)?1:0))));
LiteralArgumentBuilder<ServerCommandSource> d = literal("download").requires((player) -> SettingsManager.canUseCommand(player, CarpetSettings.commandScriptACE)).
then(literal("global").then(argument("path", StringArgumentType.greedyString()).suggests(ScriptCommand::suggestDownloadableApps).executes(cc-> AppStoreManager.downloadScript(cc, StringArgumentType.getString(cc,"path"), true)))).
then(literal("local").then(argument("path", StringArgumentType.greedyString()).suggests(ScriptCommand::suggestDownloadableApps).executes(cc-> AppStoreManager.downloadScript(cc, StringArgumentType.getString(cc,"path"), false))));
then(argument("path", StringArgumentType.greedyString()).
suggests(ScriptCommand::suggestDownloadableApps).
executes(cc-> AppStoreManager.downloadScript(cc.getSource(), StringArgumentType.getString(cc,"path"))));
dispatcher.register(literal("script").
requires((player) -> SettingsManager.canUseCommand(player, CarpetSettings.commandScript)).
@@ -12,8 +12,10 @@ import carpet.script.exception.CarpetExpressionException;
import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.InvalidCallbackException;
import carpet.script.utils.AppStoreManager;
import carpet.script.value.EntityValue;
import carpet.script.value.FunctionValue;
import carpet.script.value.ListValue;
import carpet.script.value.MapValue;
import carpet.script.value.NumericValue;
import carpet.script.value.StringValue;
@@ -78,6 +80,7 @@ public class CarpetScriptHost extends ScriptHost
Predicate<ServerCommandSource> commandValidator;
boolean isRuleApp;
public AppStoreManager.StoreNode storeSource;
private CarpetScriptHost(CarpetScriptServer server, Module code, boolean perUser, ScriptHost parent, Map<Value, Value> config, Map<String, CommandArgument> argTypes, Predicate<ServerCommandSource> commandValidator, boolean isRuleApp)
{
@@ -98,9 +101,10 @@ public class CarpetScriptHost extends ScriptHost
appArgTypes = argTypes;
this.commandValidator = commandValidator;
this.isRuleApp = isRuleApp;
storeSource = null;
}
public static CarpetScriptHost create(CarpetScriptServer scriptServer, Module module, boolean perPlayer, ServerCommandSource source, Predicate<ServerCommandSource> commandValidator, boolean isRuleApp)
public static CarpetScriptHost create(CarpetScriptServer scriptServer, Module module, boolean perPlayer, ServerCommandSource source, Predicate<ServerCommandSource> commandValidator, boolean isRuleApp, AppStoreManager.StoreNode storeSource)
{
CarpetScriptHost host = new CarpetScriptHost(scriptServer, module, perPlayer, null, Collections.emptyMap(), new HashMap<>(), commandValidator, isRuleApp);
// parse code and convert to expression
@@ -117,6 +121,7 @@ public class CarpetScriptHost extends ScriptHost
host.setChatErrorSnooper(source);
CarpetExpression ex = new CarpetExpression(host.main, code, source, new BlockPos(0, 0, 0));
ex.getExpr().asATextSource();
host.storeSource = storeSource;
ex.scriptRunCommand(host, new BlockPos(source.getPosition()));
}
catch (CarpetExpressionException e)
@@ -130,6 +135,10 @@ public class CarpetScriptHost extends ScriptHost
host.handleErrorWithStack("Math doesn't compute", ae);
return null;
}
finally
{
host.storeSource = null;
}
}
return host;
}
@@ -302,8 +311,19 @@ public class CarpetScriptHost extends ScriptHost
else
{
checkModVersionRequirements(loadRequirements);
};
if (storeSource != null)
{
Value resources = config.get(new StringValue("resources"));
if (resources != null)
{
if (!(resources instanceof ListValue)) throw new InternalExpressionException("App resources not defined as a list");
for (Value resource : ((ListValue) resources).getItems())
{
AppStoreManager.addResource(this, storeSource, resource);
}
}
}
appConfig = config;
}
catch (NullPointerException ignored)
@@ -21,6 +21,7 @@ import carpet.script.language.Functions;
import carpet.script.language.Loops;
import carpet.script.language.Sys;
import carpet.script.language.Threading;
import carpet.script.utils.AppStoreManager;
import carpet.script.value.FunctionValue;
import carpet.script.value.Value;
import carpet.utils.CarpetProfiler;
@@ -54,9 +55,6 @@ import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;
public class CarpetScriptServer
{
//make static for now, but will change that later:
@@ -127,7 +125,7 @@ public class CarpetScriptServer
tickStart = 0L;
stopAll = false;
holyMoly = server.getCommandManager().getDispatcher().getRoot().getChildren().stream().map(CommandNode::getName).collect(Collectors.toSet());
globalHost = CarpetScriptHost.create(this, null, false, null, p -> true, false);
globalHost = CarpetScriptHost.create(this, null, false, null, p -> true, false, null);
}
public void initializeForWorld()
@@ -142,7 +140,7 @@ public class CarpetScriptServer
{
for (String moduleName: listAvailableModules(false))
{
addScriptHost(server.getCommandSource(), moduleName, null, true, true, false);
addScriptHost(server.getCommandSource(), moduleName, null, true, true, false, null);
}
}
CarpetEventServer.Event.START.onTick();
@@ -241,7 +239,7 @@ public class CarpetScriptServer
}
public boolean addScriptHost(ServerCommandSource source, String name, Predicate<ServerCommandSource> commandValidator,
boolean perPlayer, boolean autoload, boolean isRuleApp)
boolean perPlayer, boolean autoload, boolean isRuleApp, AppStoreManager.StoreNode installer)
{
CarpetProfiler.ProfilerToken currentSection = CarpetProfiler.start_section(null, "Scarpet load", CarpetProfiler.TYPE.GENERAL);
if (commandValidator == null) commandValidator = p -> true;
@@ -260,7 +258,7 @@ public class CarpetScriptServer
Messenger.m(source, "r Failed to add "+name+" app");
return false;
}
CarpetScriptHost newHost = CarpetScriptHost.create(this, module, perPlayer, source, commandValidator, isRuleApp);
CarpetScriptHost newHost = CarpetScriptHost.create(this, module, perPlayer, source, commandValidator, isRuleApp, installer);
if (newHost == null)
{
Messenger.m(source, "r Failed to add "+name+" app");
@@ -488,7 +486,7 @@ public class CarpetScriptServer
apps.keySet().forEach(s -> removeScriptHost(server.getCommandSource(), s, false, false));
CarpetEventServer.Event.clearAllBuiltinEvents();
init();
apps.forEach((s, data) -> addScriptHost(server.getCommandSource(), s,data.commandValidator, data.perUser,false, data.isRuleApp));
apps.forEach((s, data) -> addScriptHost(server.getCommandSource(), s,data.commandValidator, data.perUser,false, data.isRuleApp, null));
}
public void reAddCommands()
@@ -1,5 +1,8 @@
package carpet.script.utils;
import carpet.CarpetServer;
import carpet.script.CarpetScriptHost;
import carpet.script.value.Value;
import carpet.settings.ParsedRule;
import carpet.settings.Validator;
import carpet.utils.Messenger;
@@ -7,12 +10,11 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.brigadier.context.CommandContext;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.command.CommandException;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.util.WorldSavePath;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import java.io.BufferedReader;
import java.io.FileWriter;
@@ -44,12 +46,18 @@ public class AppStoreManager
/** A local copy of the scarpet repo's file structure, to avoid multiple queries to github.com while typing out the
* {@code /script download} command and getting the suggestions.
*/
public static final PathNode appStoreRoot = PathNode.folder(null, "");
public static final StoreNode appStoreRoot = StoreNode.folder(null, "");
/** This is the base link to the scarpet app repo from the github api.
*/
private static String scarpetRepoLink = "https://api.github.com/repos/gnembon/scarpet/contents/programs/";
public static void addResource(CarpetScriptHost carpetScriptHost, StoreNode storeSource, Value resource)
{
// todo
// locate online file, download to specified location
}
public static class ScarpetAppStoreValidator extends Validator<String>
{
@Override public String validate(ServerCommandSource source, ParsedRule<String> currentRule, String newValue, String string)
@@ -69,25 +77,25 @@ public class AppStoreManager
public String description() { return "Appstore link should point to a valid github repository";}
}
public static class PathNode
public static class StoreNode
{
public String name;
public PathNode parent;
public Map<String, PathNode> children;
public StoreNode parent;
public Map<String, StoreNode> children;
public boolean sealed;
public String value;
public static PathNode folder(PathNode parent, String name)
public static StoreNode folder(StoreNode parent, String name)
{
PathNode node = new PathNode(parent, name);
StoreNode node = new StoreNode(parent, name);
node.children = new HashMap<>();
node.value = null;
node.sealed = false;
return node;
}
public static PathNode scriptFile(PathNode parent, String name, String value)
public static StoreNode scriptFile(StoreNode parent, String name, String value)
{
PathNode node = new PathNode(parent, name);
StoreNode node = new StoreNode(parent, name);
node.children = null;
node.value = value;
node.sealed = true;
@@ -110,7 +118,7 @@ public class AppStoreManager
{
return this == appStoreRoot ? new StringBuilder() : parent.createPrePath().append(pathElement());
}
private PathNode(PathNode parent, String name)
private StoreNode(StoreNode parent, String name)
{
this.parent = parent;
this.name = name;
@@ -175,7 +183,7 @@ public class AppStoreManager
return children.values().stream().map(s -> prefix+s.pathElement().replaceAll("/$", "")).collect(Collectors.toList());
}
public PathNode drillDown(String pathElement) throws IOException
public StoreNode drillDown(String pathElement) throws IOException
{
if (isLeaf()) throw new IOException(pathElement+" is not a folder");
fillChildren();
@@ -185,7 +193,7 @@ public class AppStoreManager
public String getValue(String file) throws IOException
{
PathNode leaf = drillDown(file);
StoreNode leaf = drillDown(file);
if (!leaf.isLeaf()) throw new IOException(file+" is not a file");
return leaf.value;
}
@@ -201,7 +209,7 @@ public class AppStoreManager
public static List<String> suggestionsFromPath(String currentPath) throws IOException
{
String[] path = currentPath.split("/");
PathNode appKiosk = appStoreRoot;
StoreNode appKiosk = appStoreRoot;
for(String pathElement : path)
{
if (appKiosk.cannotContinueFor(pathElement)) return appKiosk.createPathSuggestions();
@@ -216,14 +224,15 @@ public class AppStoreManager
* methods to avoid repeating code and so it makes more sense what it's exactly doing.
*
* @param path The user-inputted path to the script
* @param global Whether or not we wanna save it to the local scripts folder or in the global config folder
* @return {@code 1} if we succesfully saved the script, {@code 0} otherwise
*/
public static int downloadScript(CommandContext<ServerCommandSource> cc, String path, boolean global)
public static int downloadScript(ServerCommandSource source, String path)
{
Pair<String,String> code = getScriptCode(path);
return saveScriptToFile(path, code.getLeft(), code.getRight(), cc, global);
Triple<String,String, StoreNode> code = getScriptCode(path);
if (!saveScriptToFile(source, path, code.getLeft(), code.getMiddle(), false)) return 0;
boolean success = CarpetServer.scriptServer.addScriptHost(source, code.getLeft(), null, true, false, false, code.getRight());
return success?1:0;
}
/** Gets the code once the user inputs the command.
@@ -231,10 +240,10 @@ public class AppStoreManager
* @param appPath The user inputted path to the scarpet script
* @return Pair of app file name and content
*/
public static Pair<String,String> getScriptCode(String appPath)
public static Triple<String,String, StoreNode> getScriptCode(String appPath)
{
String[] path = appPath.split("/");
PathNode appKiosk = appStoreRoot;
StoreNode appKiosk = appStoreRoot;
try
{
for(String pathElement : Arrays.copyOfRange(path, 0, path.length-1))
@@ -242,7 +251,7 @@ public class AppStoreManager
String appName = path[path.length-1];
URL appURL = new URL(appKiosk.getValue(appName));
HttpURLConnection http = (HttpURLConnection) appURL.openConnection();
return Pair.of(appName, getStringFromStream((InputStream) http.getContent()));
return Triple.of(appName, getStringFromStream((InputStream) http.getContent()), appKiosk);
}
catch (IOException e)
{
@@ -250,43 +259,36 @@ public class AppStoreManager
}
}
public static int saveScriptToFile(String path, String appFileName, String code, CommandContext<ServerCommandSource> cc, boolean globalSavePath){
public static boolean saveScriptToFile(ServerCommandSource source, String path, String appFileName, String code, boolean globalSavePath){
String scriptPath;
String message;
if(globalSavePath && !cc.getSource().getMinecraftServer().isDedicated())
String location;
if(globalSavePath && !source.getMinecraftServer().isDedicated())
{ //cos config folder only is in clients
scriptPath = FabricLoader.getInstance().getConfigDir().resolve("carpet/scripts/appstore").toAbsolutePath()+"/"+path;
message = "global script config folder";
location = "global script config folder";
}
else
{
scriptPath = cc.getSource().getMinecraftServer().getSavePath(WorldSavePath.ROOT).resolve("scripts").toAbsolutePath()+"/"+appFileName;
message = "world scripts folder";
scriptPath = source.getMinecraftServer().getSavePath(WorldSavePath.ROOT).resolve("scripts").toAbsolutePath()+"/"+appFileName;
location = "world scripts folder";
}
try
{
Path scriptLocation = Paths.get(scriptPath);
Path scriptFolderLocation = Paths.get(scriptPath.substring(0, scriptPath.lastIndexOf('/')));//folder location without file name
if (!Files.exists(scriptFolderLocation))
Files.createDirectories(scriptFolderLocation);
Files.createDirectories(scriptLocation.getParent());
if(Files.exists(scriptLocation))
Messenger.m(cc.getSource(), String.format("gi Note: overwriting existing file '%s'", appFileName));
Messenger.m(cc.getSource(), "gi Placing script in " + message);
Messenger.m(source, String.format("gi Note: overwriting existing app '%s'", appFileName));
FileWriter fileWriter = new FileWriter(scriptPath);
fileWriter.write(code);
fileWriter.close();
}
catch (IOException e)
{
Messenger.m(cc.getSource(), "r Error in downloading script");
return 0;
Messenger.m(source, "r Error in downloading script: "+e.getMessage());
return false;
}
Messenger.m(cc.getSource(), "gi Successfully created "+ appFileName + " in " + message);
return 1;
Messenger.m(source, "gi Successfully created "+ appFileName + " in " + location);
return true;
}
/** Returns the string from the inputstream gotten from the html request.
@@ -298,28 +300,23 @@ public class AppStoreManager
*/
public static String getStringFromStream(InputStream inputStream) throws IOException
{
if (inputStream != null)
{
Writer stringWriter = new StringWriter();
if (inputStream == null)
throw new IOException("No app to be found on the appstore");
char[] charBuffer = new char[2048];
try
{
Reader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
int counter;
while ((counter = reader.read(charBuffer)) != -1)
stringWriter.write(charBuffer, 0, counter);
}
finally
{
inputStream.close();
}
return stringWriter.toString();
}
else
Writer stringWriter = new StringWriter();
char[] charBuffer = new char[2048];
try
{
return "";
Reader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
int counter;
while ((counter = reader.read(charBuffer)) != -1)
stringWriter.write(charBuffer, 0, counter);
}
finally
{
inputStream.close();
}
return stringWriter.toString();
}
}
@@ -193,7 +193,7 @@ public class SettingsManager
{
if (rule.getBoolValue() || (rule.type == String.class && !rule.get().equals("false")))
{
CarpetServer.scriptServer.addScriptHost(source, rule.scarpetApp, s -> canUseCommand(s, rule.get()), false, false, true);
CarpetServer.scriptServer.addScriptHost(source, rule.scarpetApp, s -> canUseCommand(s, rule.get()), false, false, true, null);
} else {
CarpetServer.scriptServer.removeScriptHost(source, rule.scarpetApp, false, true);
}