Merge socket-module into latest

This commit is contained in:
Victor 2016-08-02 23:19:07 +03:00
commit da36a3417c
6 changed files with 341 additions and 83 deletions

View File

@ -53,7 +53,9 @@ task proguard(dependsOn: dist, type: proguard.gradle.ProGuardTask) {
}
dependencies {
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile ('io.socket:socket.io-client:0.7.0') {
exclude group: 'org.json', module: 'json'
}
compile 'org.json:json:20160212'
testCompile 'junit:junit:4.12'

View File

@ -5,6 +5,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
/**
*
@ -31,6 +32,18 @@ public class MapValue implements Value, Iterable<Map.Entry<Value, Value>> {
this.map = map;
}
public boolean ifPresent(String key, Consumer<Value> consumer) {
return ifPresent(new StringValue(key), consumer);
}
public boolean ifPresent(Value key, Consumer<Value> consumer) {
if (map.containsKey(key)) {
consumer.accept(map.get(key));
return true;
}
return false;
}
public ArrayValue toPairs() {
final int size = map.size();
final ArrayValue result = new ArrayValue(size);

View File

@ -0,0 +1,83 @@
package com.annimon.ownlang.lib;
import java.util.Iterator;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONObject;
public final class ValueUtils {
public static Object toObject(Value val) {
switch (val.type()) {
case Types.ARRAY:
return toObject((ArrayValue) val);
case Types.MAP:
return toObject((MapValue) val);
case Types.NUMBER:
return val.raw();
case Types.STRING:
return val.asString();
default:
return JSONObject.NULL;
}
}
public static Object toObject(MapValue map) {
final JSONObject result = new JSONObject();
for (Map.Entry<Value, Value> entry : map) {
final String key = entry.getKey().asString();
final Object value = toObject(entry.getValue());
result.put(key, value);
}
return result;
}
public static Object toObject(ArrayValue array) {
final JSONArray result = new JSONArray();
for (Value value : array) {
result.put(toObject(value));
}
return result;
}
public static Value toValue(Object obj) {
if (obj instanceof JSONObject) {
return toValue((JSONObject) obj);
}
if (obj instanceof JSONArray) {
return toValue((JSONArray) obj);
}
if (obj instanceof String) {
return new StringValue((String) obj);
}
if (obj instanceof Number) {
return NumberValue.of(((Number) obj));
}
if (obj instanceof Boolean) {
return NumberValue.fromBoolean((Boolean) obj);
}
// NULL or other
return NumberValue.ZERO;
}
public static MapValue toValue(JSONObject json) {
final MapValue result = new MapValue(json.length());
final Iterator<String> it = json.keys();
while(it.hasNext()) {
final String key = it.next();
final Value value = toValue(json.get(key));
result.set(new StringValue(key), value);
}
return result;
}
public static ArrayValue toValue(JSONArray json) {
final int length = json.length();
final ArrayValue result = new ArrayValue(length);
for (int i = 0; i < length; i++) {
final Value value = toValue(json.get(i));
result.set(i, value);
}
return result;
}
}

View File

@ -1,8 +1,12 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.lib.*;
import java.util.Iterator;
import org.json.*;
import com.annimon.ownlang.lib.Arguments;
import com.annimon.ownlang.lib.Function;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.ValueUtils;
import org.json.JSONException;
import org.json.JSONTokener;
public final class json_decode implements Function {
@ -12,50 +16,9 @@ public final class json_decode implements Function {
try {
final String jsonRaw = args[0].asString();
final Object root = new JSONTokener(jsonRaw).nextValue();
return process(root);
return ValueUtils.toValue(root);
} catch (JSONException ex) {
throw new RuntimeException("Error while parsing json", ex);
}
}
private Value process(Object obj) {
if (obj instanceof JSONObject) {
return process((JSONObject) obj);
}
if (obj instanceof JSONArray) {
return process((JSONArray) obj);
}
if (obj instanceof String) {
return new StringValue((String) obj);
}
if (obj instanceof Number) {
return NumberValue.of(((Number) obj));
}
if (obj instanceof Boolean) {
return NumberValue.fromBoolean((Boolean) obj);
}
// NULL or other
return NumberValue.ZERO;
}
private MapValue process(JSONObject json) {
final MapValue result = new MapValue(json.length());
final Iterator<String> it = json.keys();
while(it.hasNext()) {
final String key = it.next();
final Value value = process(json.get(key));
result.set(new StringValue(key), value);
}
return result;
}
private ArrayValue process(JSONArray json) {
final int length = json.length();
final ArrayValue result = new ArrayValue(length);
for (int i = 0; i < length; i++) {
final Value value = process(json.get(i));
result.set(i, value);
}
return result;
}
}

View File

@ -1,8 +1,13 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.lib.*;
import java.util.Map;
import org.json.*;
import com.annimon.ownlang.lib.Arguments;
import com.annimon.ownlang.lib.Function;
import com.annimon.ownlang.lib.StringValue;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.ValueUtils;
import org.json.JSONException;
import org.json.JSONObject;
public final class json_encode implements Function {
@ -10,44 +15,11 @@ public final class json_encode implements Function {
public Value execute(Value... args) {
Arguments.check(1, args.length);
try {
final Object root = process(args[0]);
final Object root = ValueUtils.toObject(args[0]);
final String jsonRaw = JSONObject.valueToString(root);
return new StringValue(jsonRaw);
} catch (JSONException ex) {
throw new RuntimeException("Error while creating json", ex);
}
}
private Object process(Value val) {
switch (val.type()) {
case Types.ARRAY:
return process((ArrayValue) val);
case Types.MAP:
return process((MapValue) val);
case Types.NUMBER:
return val.raw();
case Types.STRING:
return val.asString();
default:
return JSONObject.NULL;
}
}
private Object process(MapValue map) {
final JSONObject result = new JSONObject();
for (Map.Entry<Value, Value> entry : map) {
final String key = entry.getKey().asString();
final Object value = process(entry.getValue());
result.put(key, value);
}
return result;
}
private Object process(ArrayValue array) {
final JSONArray result = new JSONArray();
for (Value value : array) {
result.put(process(value));
}
return result;
}
}

View File

@ -0,0 +1,225 @@
package com.annimon.ownlang.lib.modules;
import com.annimon.ownlang.annotations.ConstantInitializer;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.*;
import io.socket.client.IO;
import io.socket.client.Socket;
import java.net.URISyntaxException;
/**
* socket.io module.
*
* @author aNNiMON
*/
@ConstantInitializer
public final class socket implements Module {
public static void initConstants() {
Variables.define("EVENT_CONNECT", new StringValue(Socket.EVENT_CONNECT));
Variables.define("EVENT_CONNECTING", new StringValue(Socket.EVENT_CONNECTING));
Variables.define("EVENT_CONNECT_ERROR", new StringValue(Socket.EVENT_CONNECT_ERROR));
Variables.define("EVENT_CONNECT_TIMEOUT", new StringValue(Socket.EVENT_CONNECT_TIMEOUT));
Variables.define("EVENT_DISCONNECT", new StringValue(Socket.EVENT_DISCONNECT));
Variables.define("EVENT_ERROR", new StringValue(Socket.EVENT_ERROR));
Variables.define("EVENT_MESSAGE", new StringValue(Socket.EVENT_MESSAGE));
Variables.define("EVENT_PING", new StringValue(Socket.EVENT_PING));
Variables.define("EVENT_PONG", new StringValue(Socket.EVENT_PONG));
Variables.define("EVENT_RECONNECT", new StringValue(Socket.EVENT_RECONNECT));
Variables.define("EVENT_RECONNECTING", new StringValue(Socket.EVENT_RECONNECTING));
Variables.define("EVENT_RECONNECT_ATTEMPT", new StringValue(Socket.EVENT_RECONNECT_ATTEMPT));
Variables.define("EVENT_RECONNECT_ERROR", new StringValue(Socket.EVENT_RECONNECT_ERROR));
Variables.define("EVENT_RECONNECT_FAILED", new StringValue(Socket.EVENT_RECONNECT_FAILED));
}
@Override
public void init() {
initConstants();
Functions.set("newSocket", socket::newSocket);
}
private static Value newSocket(Value... args) {
Arguments.checkOrOr(1, 2, args.length);
try {
final String url = args[0].asString();
if (args.length == 1) {
return new SocketValue(IO.socket(url));
}
if (args[1].type() != Types.MAP) {
throw new TypeException("Map expected in second argument");
}
IO.Options options = parseOptions((MapValue) args[1]);
return new SocketValue(IO.socket(url, options));
} catch (URISyntaxException ue) {
return NumberValue.MINUS_ONE;
}
}
private static class SocketValue extends MapValue {
private final Socket socket;
public SocketValue(Socket socket) {
super(11);
this.socket = socket;
init();
}
private void init() {
set("close", this::close);
set("connect", this::connect);
set("connected", this::connected);
set("disconnect", this::disconnect);
set("emit", this::emit);
set("hasListeners", this::hasListeners);
set("id", this::id);
set("off", this::off);
set("on", this::on);
set("once", this::once);
set("open", this::open);
set("send", this::send);
}
private Value close(Value... args) {
socket.close();
return this;
}
private Value connect(Value... args) {
socket.connect();
return this;
}
private Value connected(Value... args) {
return NumberValue.fromBoolean(socket.connected());
}
private Value disconnect(Value... args) {
socket.disconnect();
return this;
}
private Value hasListeners(Value... args) {
Arguments.check(1, args.length);
return NumberValue.fromBoolean(
socket.hasListeners(args[0].asString())
);
}
private Value emit(Value... args) {
Arguments.checkOrOr(2, 3, args.length);
final String event = args[0].asString();
final Value value = args[1];
if (args.length == 3) {
// TODO ack
}
socket.emit(event, ValueUtils.toObject(value));
return this;
}
private Value id(Value... args) {
return new StringValue(socket.id());
}
private Value off(Value... args) {
Arguments.checkOrOr(0, 1, args.length);
if (args.length == 1) {
socket.off(args[0].asString());
} else {
socket.off();
}
return this;
}
private Value on(Value... args) {
Arguments.check(2, args.length);
final String event = args[0].asString();
final Function listener = ((FunctionValue) args[1]).getValue();
socket.on(event, sArgs -> {
executeSocketListener(listener, sArgs);
});
return this;
}
private Value once(Value... args) {
Arguments.check(2, args.length);
final String event = args[0].asString();
final Function listener = ((FunctionValue) args[1]).getValue();
socket.once(event, sArgs -> {
executeSocketListener(listener, sArgs);
});
return this;
}
private Value open(Value... args) {
socket.open();
return this;
}
private Value send(Value... args) {
Arguments.check(1, args.length);
socket.send(ValueUtils.toObject(args[0]));
return this;
}
private void executeSocketListener(Function listener, Object[] sArgs) {
if (sArgs == null) {
listener.execute(new ArrayValue(0));
} else {
int size = sArgs.length;
final Value[] fArgs = new Value[size];
for (int i = 0; i < size; i++) {
fArgs[i] = ValueUtils.toValue(sArgs[i]);
}
listener.execute(new ArrayValue(fArgs));
}
}
}
private static IO.Options parseOptions(MapValue map) {
final IO.Options result = new IO.Options();
map.ifPresent("forceNew", v -> result.forceNew = v.asInt() != 0);
map.ifPresent("multiplex", v -> result.multiplex = v.asInt() != 0);
map.ifPresent("reconnection", v -> result.reconnection = v.asInt() != 0);
map.ifPresent("rememberUpgrade", v -> result.rememberUpgrade = v.asInt() != 0);
map.ifPresent("secure", v -> result.secure = v.asInt() != 0);
map.ifPresent("timestampRequests", v -> result.timestampRequests = v.asInt() != 0);
map.ifPresent("upgrade", v -> result.upgrade = v.asInt() != 0);
map.ifPresent("policyPort", v -> result.policyPort = v.asInt());
map.ifPresent("port", v -> result.port = v.asInt());
map.ifPresent("reconnectionAttempts", v -> result.reconnectionAttempts = v.asInt());
map.ifPresent("reconnectionDelay", v -> result.reconnectionDelay = getNumber(v).longValue());
map.ifPresent("reconnectionDelayMax", v -> result.reconnectionDelayMax = getNumber(v).longValue());
map.ifPresent("timeout", v -> result.timeout = getNumber(v).longValue());
map.ifPresent("randomizationFactor", v -> result.randomizationFactor = v.asNumber());
map.ifPresent("host", v -> result.host = v.asString());
map.ifPresent("hostname", v -> result.hostname = v.asString());
map.ifPresent("path", v -> result.path = v.asString());
map.ifPresent("query", v -> result.query = v.asString());
map.ifPresent("timestampParam", v -> result.timestampParam = v.asString());
map.ifPresent("transports", v -> {
if (v.type() != Types.ARRAY) return;
final ArrayValue arr = (ArrayValue) v;
final String[] values = new String[arr.size()];
int index = 0;
for (Value value : arr) {
values[index++] = value.asString();
}
result.transports = values;
});
return result;
}
private static Number getNumber(Value value) {
if (value.type() != Types.NUMBER) return value.asInt();
return ((NumberValue) value).raw();
}
}