Skip to content

Commit

Permalink
Start work on more flexible JSON parsing API
Browse files Browse the repository at this point in the history
  • Loading branch information
UnknownShadow200 committed Jan 16, 2021
1 parent d1f55f7 commit 458636b
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 49 deletions.
27 changes: 10 additions & 17 deletions MCGalaxy/Commands/Moderation/CmdLocation.cs
Expand Up @@ -30,12 +30,6 @@ public class CmdLocation : Command2 {
get { return new[] { new CommandPerm(LevelPermission.Admin, "can see state/province") }; }
}

class GeoInfo {
[ConfigString] public string region;
[ConfigString] public string country;
}
static ConfigElement[] elems;

public override void Use(Player p, string message, CommandData data) {
if (message.Length == 0) {
if (p.IsSuper) { SuperRequiresArgs(p, "player name or IP"); return; }
Expand All @@ -49,24 +43,23 @@ class GeoInfo {
p.Message("%WPlayer has an internal IP, cannot trace"); return;
}

bool success;
string ipInfo;
string json, region = null, country = null;
using (WebClient client = HttpUtil.CreateWebClient()) {
ipInfo = client.DownloadString("http://ipinfo.io/" + ip + "/geo");
json = client.DownloadString("http://ipinfo.io/" + ip + "/geo");
}

JsonObject obj = (JsonObject)Json.Parse(ipInfo, out success);
GeoInfo info = new GeoInfo();
if (obj == null || !success) {
p.Message("%WError parsing GeoIP info"); return;
}
JsonContext ctx = new JsonContext(json);
ctx.OnMember = (obj, key, value) => {
if (key == "region") region = (string)value;
if (key == "country") country = (string)value;
};

if (elems == null) elems = ConfigElement.GetAll(typeof(GeoInfo));
obj.Deserialise(elems, info);
Json.Parse(ctx);
if (!ctx.Success) { p.Message("%WError parsing GeoIP info"); return; }

string suffix = HasExtraPerm(p, data.Rank, 1) ? "&b{1}%S/&b{2}" : "&b{2}";
string nick = name == null ? ip : "of " + p.FormatNick(name);
p.Message("The IP {0} %Straces to: " + suffix, nick, info.region, info.country);
p.Message("The IP {0} %Straces to: " + suffix, nick, region, country);
}

public override void Help(Player p) {
Expand Down
45 changes: 27 additions & 18 deletions MCGalaxy/Config/JSON.cs
Expand Up @@ -20,12 +20,25 @@ public sealed class JsonObject {
}
}

public delegate void JsonOnMember(JsonObject obj, string key, object value);
public sealed class JsonContext {
public string Val; public bool Success;
public JsonOnMember OnMember;

internal int Idx;
internal char Cur { get { return Val[Idx]; } }
internal StringBuilder strBuffer = new StringBuilder(96);

public JsonContext(string value) {
Val = value;
Success = true;
OnMember = DefaultOnMember;
}

static void DefaultOnMember(JsonObject obj, string key, object value) {
obj.Keys.Add(key);
obj.Values.Add(value);
}
}

public static class Json {
Expand Down Expand Up @@ -64,21 +77,18 @@ public static class Json {
// invalid token
ctx.Idx++; return T_NONE;
}

static object ParseStream(JsonContext ctx) {
return ParseValue(NextToken(ctx), ctx);
}


public static object Parse(string s, out bool success) {
JsonContext ctx = new JsonContext();
ctx.Val = s;
ctx.Success = true;

object obj = ParseStream(ctx);
success = ctx.Success;
JsonContext ctx = new JsonContext(s);
object obj = Parse(ctx);
success = ctx.Success;
return obj;
}

public static object Parse(JsonContext ctx) {
return ParseValue(NextToken(ctx), ctx);
}

static object ParseValue(int token, JsonContext ctx) {
switch (token) {
case '{': return ParseObject(ctx);
Expand All @@ -95,11 +105,11 @@ public static class Json {
}

static JsonObject ParseObject(JsonContext ctx) {
JsonObject members = new JsonObject();
JsonObject obj = new JsonObject();
while (true) {
int token = NextToken(ctx);
if (token == ',') continue;
if (token == '}') return members;
if (token == '}') return obj;

if (token != '"') { ctx.Success = false; return null; }
string key = ParseString(ctx);
Expand All @@ -111,20 +121,19 @@ public static class Json {
if (token == T_NONE) { ctx.Success = false; return null; }

object value = ParseValue(token, ctx);
members.Keys.Add(key);
members.Values.Add(value);
ctx.OnMember(obj, key, value);
}
}

static JsonArray ParseArray(JsonContext ctx) {
JsonArray elements = new JsonArray();
JsonArray arr = new JsonArray();
while (true) {
int token = NextToken(ctx);
if (token == ',') continue;
if (token == ']') return elements;
if (token == ']') return arr;

if (token == T_NONE) { ctx.Success = false; return null; }
elements.Add(ParseValue(token, ctx));
arr.Add(ParseValue(token, ctx));
}
}

Expand Down
28 changes: 14 additions & 14 deletions MCGalaxy/Network/Heartbeat/ClassiCube.cs
Expand Up @@ -108,23 +108,23 @@ public sealed class ClassiCubeBeat : Heartbeat {
}

static string GetError(string json) {
bool success;
JsonObject obj = (JsonObject)Json.Parse(json, out success);
if (obj == null) return null;
JsonContext ctx = new JsonContext(json);
string error = null;

for (int i = 0; i < obj.Keys.Count; i++) {
if (!obj.Keys[i].CaselessEq("errors")) continue;
object value = obj.Values[i];
if (value == null) return null;
// silly design, but form of json is: "errors": [ ["Error1"], ["Error2"] ]
ctx.OnMember = (obj, key, value) => {
if (key != "errors") return;
JsonArray errors = value as JsonArray;
if (errors == null) return;
// silly design, but form of json is: "errors": [ ["Error1"], ["Error2"] ]
JsonArray errors = (JsonArray)value;
foreach (object raw in errors) {
JsonArray error = raw as JsonArray;
if (error != null && error.Count > 0) return (string)error[0];
}
}
return null;
JsonArray err = raw as JsonArray;
if (err != null && err.Count > 0) error = (string)err[0];
}
};

Json.Parse(ctx);
return error;
}
}
}

0 comments on commit 458636b

Please sign in to comment.