feat(debug): use json socket to connect to remote debug client
This commit is contained in:
@@ -1,187 +0,0 @@
|
|||||||
package org.autojs.autojs.pluginclient;
|
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import org.autojs.autojs.tool.SimpleObserver;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
import io.reactivex.subjects.PublishSubject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Stardust on 2017/5/10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class DevPluginClient {
|
|
||||||
|
|
||||||
public static class State {
|
|
||||||
|
|
||||||
public static final int DISCONNECTED = 0;
|
|
||||||
public static final int CONNECTING = 1;
|
|
||||||
public static final int CONNECTED = 2;
|
|
||||||
|
|
||||||
private final int mState;
|
|
||||||
private final Throwable mException;
|
|
||||||
|
|
||||||
public State(int state, Throwable exception) {
|
|
||||||
mState = state;
|
|
||||||
mException = exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
public State(int state) {
|
|
||||||
this(state, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getState() {
|
|
||||||
return mState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Throwable getException() {
|
|
||||||
return mException;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final State STATE_CONNECTED = new State(State.CONNECTED);
|
|
||||||
private static final State STATE_CONNECTING = new State(State.CONNECTING);
|
|
||||||
|
|
||||||
private volatile Socket mSocket;
|
|
||||||
private Handler mResponseHandler;
|
|
||||||
private String host;
|
|
||||||
private int port;
|
|
||||||
private OutputStream mOutputStream;
|
|
||||||
private final PublishSubject<State> mConnection;
|
|
||||||
private int mState;
|
|
||||||
|
|
||||||
public DevPluginClient(String host, int port, PublishSubject<State> connection) {
|
|
||||||
this.host = host;
|
|
||||||
this.port = port;
|
|
||||||
mConnection = connection;
|
|
||||||
mConnection.subscribe(state -> mState = state.getState());
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getState() {
|
|
||||||
return mState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setResponseHandler(Handler handler) {
|
|
||||||
mResponseHandler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void connectToServer() {
|
|
||||||
if (mState != State.DISCONNECTED) {
|
|
||||||
throw new IllegalStateException("Connecting or Connected!");
|
|
||||||
}
|
|
||||||
new Thread(() -> {
|
|
||||||
if (mState != State.DISCONNECTED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mConnection.onNext(STATE_CONNECTING);
|
|
||||||
try {
|
|
||||||
connect();
|
|
||||||
if (mSocket != null)
|
|
||||||
readDataFromSocket();
|
|
||||||
close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
close();
|
|
||||||
mConnection.onNext(new State(State.DISCONNECTED, e));
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void readDataFromSocket() throws IOException {
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
|
|
||||||
JsonParser parser = new JsonParser();
|
|
||||||
while (!Thread.currentThread().isInterrupted()) {
|
|
||||||
String line = reader.readLine();
|
|
||||||
if (line == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mResponseHandler != null) {
|
|
||||||
handleData(parser, line);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleData(JsonParser parser, String line) {
|
|
||||||
try {
|
|
||||||
JsonElement jsonElement = parser.parse(line);
|
|
||||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
|
||||||
mResponseHandler.handle(jsonObject);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
//ignore exception thrown by data handler
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void connect() throws IOException {
|
|
||||||
mSocket = new Socket(host, port);
|
|
||||||
mConnection.onNext(STATE_CONNECTED);
|
|
||||||
mOutputStream = mSocket.getOutputStream();
|
|
||||||
sendDeviceName();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendDeviceName() {
|
|
||||||
JsonObject object = new JsonObject();
|
|
||||||
object.addProperty("type", "device_name");
|
|
||||||
object.addProperty("device_name", Build.BRAND + " " + Build.MODEL);
|
|
||||||
send(object).subscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Observable<JsonObject> send(final JsonObject object) {
|
|
||||||
if (mState != State.CONNECTED) {
|
|
||||||
throw new IllegalStateException("Not connected!");
|
|
||||||
}
|
|
||||||
return Observable.fromCallable(() -> {
|
|
||||||
mOutputStream.write(object.toString().getBytes());
|
|
||||||
mOutputStream.write("\n".getBytes());
|
|
||||||
mOutputStream.flush();
|
|
||||||
return object;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public Observable<JsonObject> send(Map<String, Object> data) {
|
|
||||||
JsonObject object = new JsonObject();
|
|
||||||
for (Map.Entry<String, Object> entry : data.entrySet()) {
|
|
||||||
Object value = entry.getValue();
|
|
||||||
if (value instanceof Number) {
|
|
||||||
object.addProperty(entry.getKey(), (Number) value);
|
|
||||||
} else if (value instanceof Boolean) {
|
|
||||||
object.addProperty(entry.getKey(), (Boolean) value);
|
|
||||||
} else if (value instanceof Character) {
|
|
||||||
object.addProperty(entry.getKey(), (Character) value);
|
|
||||||
} else {
|
|
||||||
object.addProperty(entry.getKey(), value.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return send(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean close() {
|
|
||||||
if (mSocket != null) {
|
|
||||||
try {
|
|
||||||
mSocket.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
mSocket = null;
|
|
||||||
mOutputStream = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -25,18 +25,18 @@ import java.util.HashMap;
|
|||||||
public class DevPluginResponseHandler implements Handler {
|
public class DevPluginResponseHandler implements Handler {
|
||||||
|
|
||||||
|
|
||||||
private Router mRouter = new Router("type")
|
private Router mRouter = new Router.RootRouter("type")
|
||||||
.handler("command", new Router("command")
|
.handler("command", new Router("command")
|
||||||
.handler("run", data -> {
|
.handler("run", data -> {
|
||||||
String script = data.get("script").getAsString();
|
String script = data.get("script").getAsString();
|
||||||
String name = getName(data);
|
String name = getName(data);
|
||||||
String viewId = data.get("view_id").getAsString();
|
String id = data.get("id").getAsString();
|
||||||
runScript(viewId, name, script);
|
runScript(id, name, script);
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
.handler("stop", data -> {
|
.handler("stop", data -> {
|
||||||
String viewId = data.get("view_id").getAsString();
|
String id = data.get("id").getAsString();
|
||||||
stopScript(viewId);
|
stopScript(id);
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.handler("save", data -> {
|
.handler("save", data -> {
|
||||||
@@ -46,11 +46,11 @@ public class DevPluginResponseHandler implements Handler {
|
|||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
.handler("rerun", data -> {
|
.handler("rerun", data -> {
|
||||||
String viewId = data.get("view_id").getAsString();
|
String id = data.get("id").getAsString();
|
||||||
String script = data.get("script").getAsString();
|
String script = data.get("script").getAsString();
|
||||||
String name = getName(data);
|
String name = getName(data);
|
||||||
stopScript(viewId);
|
stopScript(id);
|
||||||
runScript(viewId, name, script);
|
runScript(id, name, script);
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
.handler("stopAll", data -> {
|
.handler("stopAll", data -> {
|
||||||
|
|||||||
@@ -1,7 +1,19 @@
|
|||||||
package org.autojs.autojs.pluginclient;
|
package org.autojs.autojs.pluginclient;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import org.autojs.autojs.tool.EmptyObservers;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.Observer;
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
import io.reactivex.subjects.PublishSubject;
|
import io.reactivex.subjects.PublishSubject;
|
||||||
|
|
||||||
@@ -11,20 +23,48 @@ import io.reactivex.subjects.PublishSubject;
|
|||||||
|
|
||||||
public class DevPluginService {
|
public class DevPluginService {
|
||||||
|
|
||||||
|
public static class State {
|
||||||
|
|
||||||
|
public static final int DISCONNECTED = 0;
|
||||||
|
public static final int CONNECTING = 1;
|
||||||
|
public static final int CONNECTED = 2;
|
||||||
|
|
||||||
|
private final int mState;
|
||||||
|
private final Throwable mException;
|
||||||
|
|
||||||
|
public State(int state, Throwable exception) {
|
||||||
|
mState = state;
|
||||||
|
mException = exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
public State(int state) {
|
||||||
|
this(state, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getState() {
|
||||||
|
return mState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Throwable getException() {
|
||||||
|
return mException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int PORT = 9317;
|
||||||
private static DevPluginService sInstance = new DevPluginService();
|
private static DevPluginService sInstance = new DevPluginService();
|
||||||
private DevPluginClient mClient;
|
private final PublishSubject<State> mConnectionState = PublishSubject.create();
|
||||||
private final PublishSubject<DevPluginClient.State> mConnection = PublishSubject.create();
|
private volatile JsonSocket mSocket;
|
||||||
|
|
||||||
public static DevPluginService getInstance() {
|
public static DevPluginService getInstance() {
|
||||||
return sInstance;
|
return sInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
return mClient != null && mClient.getState() == DevPluginClient.State.CONNECTED;
|
return mSocket != null && !mSocket.isClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDisconnected() {
|
public boolean isDisconnected() {
|
||||||
return mClient == null || mClient.getState() == DevPluginClient.State.DISCONNECTED;
|
return mSocket == null || mSocket.isClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disconnectIfNeeded() {
|
public void disconnectIfNeeded() {
|
||||||
@@ -34,37 +74,68 @@ public class DevPluginService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
mClient.close();
|
mSocket.close();
|
||||||
mClient = null;
|
mSocket = null;
|
||||||
mConnection.onNext(new DevPluginClient.State(DevPluginClient.State.DISCONNECTED));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PublishSubject<DevPluginClient.State> getConnection() {
|
public Observable<State> connectionState() {
|
||||||
return mConnection;
|
return mConnectionState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connectToServer(String host) {
|
public Observable<JsonSocket> connectToServer(String host) {
|
||||||
int port = 1209;
|
int port = PORT;
|
||||||
String ip = host;
|
String ip = host;
|
||||||
int i = host.lastIndexOf(':');
|
int i = host.lastIndexOf(':');
|
||||||
if (i > 0 && i < host.length() - 1) {
|
if (i > 0 && i < host.length() - 1) {
|
||||||
port = Integer.parseInt(host.substring(i + 1));
|
port = Integer.parseInt(host.substring(i + 1));
|
||||||
ip = host.substring(0, i);
|
ip = host.substring(0, i);
|
||||||
}
|
}
|
||||||
mClient = new DevPluginClient(ip, port, mConnection);
|
return createSocket(ip, port)
|
||||||
mClient.setResponseHandler(new DevPluginResponseHandler());
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
mClient.connectToServer();
|
.doOnNext(socket -> mSocket = socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Observable<JsonSocket> createSocket(String ip, int port) {
|
||||||
|
return Observable.fromCallable(() -> {
|
||||||
|
JsonSocket jsonSocket = new JsonSocket(new Socket(ip, port));
|
||||||
|
DevPluginResponseHandler handler = new DevPluginResponseHandler();
|
||||||
|
jsonSocket.data()
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.doOnComplete(() -> mConnectionState.onNext(new State(State.DISCONNECTED)))
|
||||||
|
.subscribe(data -> handler.handle(data.getAsJsonObject()), e -> {
|
||||||
|
e.printStackTrace();
|
||||||
|
mConnectionState.onNext(new State(State.DISCONNECTED));
|
||||||
|
});
|
||||||
|
|
||||||
|
writePair(jsonSocket, "device_name", new Pair<>("device_name", Build.BRAND + " " + Build.MODEL));
|
||||||
|
return jsonSocket;
|
||||||
|
})
|
||||||
|
.subscribeOn(Schedulers.io());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int write(JsonSocket socket, String type, JsonObject data) throws IOException {
|
||||||
|
JsonObject json = new JsonObject();
|
||||||
|
json.addProperty("type", type);
|
||||||
|
json.add("data", data);
|
||||||
|
return socket.write(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int writePair(JsonSocket socket, String type, Pair<String, String> pair) throws IOException {
|
||||||
|
JsonObject data = new JsonObject();
|
||||||
|
data.addProperty(pair.first, pair.second);
|
||||||
|
return write(socket, type, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("CheckResult")
|
||||||
public void log(String log) {
|
public void log(String log) {
|
||||||
if (!isConnected())
|
if (!isConnected())
|
||||||
return;
|
return;
|
||||||
JsonObject object = new JsonObject();
|
JsonObject object = new JsonObject();
|
||||||
object.addProperty("type", "log");
|
object.addProperty("type", "log");
|
||||||
object.addProperty("log", log);
|
object.addProperty("log", log);
|
||||||
mClient.send(object)
|
Observable.fromCallable(() -> mSocket.write(object))
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.subscribe(ignored -> {
|
.subscribe(EmptyObservers.consumer(), Throwable::printStackTrace);
|
||||||
}, Throwable::printStackTrace);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +1,214 @@
|
|||||||
package org.autojs.autojs.pluginclient;
|
package org.autojs.autojs.pluginclient;
|
||||||
|
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.PipedInputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
import io.reactivex.subjects.PublishSubject;
|
||||||
|
|
||||||
public class JsonSocket {
|
public class JsonSocket {
|
||||||
|
|
||||||
private Socket mSocket;
|
private static final byte DELIMITER = '#';
|
||||||
|
private static final String LOG_TAG = "JsonSocket";
|
||||||
|
|
||||||
public JsonSocket(Socket socket) {
|
private final Socket mSocket;
|
||||||
|
private final JsonParser mJsonParser = new JsonParser();
|
||||||
|
private OutputStream mOutputStream;
|
||||||
|
private final PublishSubject<JsonElement> mJsonElementPublishSubject = PublishSubject.create();
|
||||||
|
private volatile boolean mClosed = false;
|
||||||
|
|
||||||
|
public JsonSocket(Socket socket) throws IOException {
|
||||||
mSocket = socket;
|
mSocket = socket;
|
||||||
|
mOutputStream = socket.getOutputStream();
|
||||||
|
new Thread(new SocketReader(socket)).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observable<JsonElement> data() {
|
||||||
|
return mJsonElementPublishSubject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int write(JsonElement element) throws IOException {
|
||||||
|
byte[] bytes = element.toString().getBytes();
|
||||||
|
String length = String.valueOf(bytes.length) + DELIMITER;
|
||||||
|
mOutputStream.write(length.getBytes());
|
||||||
|
mOutputStream.write(bytes);
|
||||||
|
Log.d(LOG_TAG, "write: length = " + bytes.length + ", json = " + element);
|
||||||
|
return bytes.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
mJsonElementPublishSubject.onComplete();
|
||||||
|
mClosed = true;
|
||||||
|
try {
|
||||||
|
mSocket.close();
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class SocketReader implements Runnable {
|
private void close(Exception e) {
|
||||||
|
if (mClosed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mJsonElementPublishSubject.onError(e);
|
||||||
|
mClosed = true;
|
||||||
|
try {
|
||||||
|
mSocket.close();
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dispatchJson(String json) {
|
||||||
|
try {
|
||||||
|
JsonElement element = mJsonParser.parse(json);
|
||||||
|
mJsonElementPublishSubject.onNext(element);
|
||||||
|
} catch (JsonParseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return mClosed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ByteQueue {
|
||||||
|
byte[] data;
|
||||||
|
int offset = 0;
|
||||||
|
int length = 0;
|
||||||
|
|
||||||
|
public ByteQueue(int initialCapacity) {
|
||||||
|
data = new byte[initialCapacity];
|
||||||
|
}
|
||||||
|
|
||||||
|
int read(InputStream stream) throws IOException {
|
||||||
|
if (length >= data.length) {
|
||||||
|
resize();
|
||||||
|
}
|
||||||
|
int end = offset + length;
|
||||||
|
int n;
|
||||||
|
if (end >= data.length) {
|
||||||
|
n = stream.read(data, 0, offset);
|
||||||
|
} else {
|
||||||
|
n = stream.read(data, end, data.length - end);
|
||||||
|
}
|
||||||
|
length += n;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void pop(int len) {
|
||||||
|
if (len > length) {
|
||||||
|
throw new IllegalArgumentException("pop " + len + " but current length is " + length);
|
||||||
|
}
|
||||||
|
offset += len;
|
||||||
|
if (offset >= data.length) {
|
||||||
|
offset -= data.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String popAsString(int len) {
|
||||||
|
if (len > length) {
|
||||||
|
throw new IllegalArgumentException("popAsString " + len + " but current length is " + length);
|
||||||
|
}
|
||||||
|
int end = offset + len;
|
||||||
|
String str;
|
||||||
|
if (end < data.length) {
|
||||||
|
str = new String(data, offset, len);
|
||||||
|
} else {
|
||||||
|
byte[] bytes = new byte[len];
|
||||||
|
System.arraycopy(data, offset, bytes, 0, data.length - offset);
|
||||||
|
System.arraycopy(data, 0, bytes, data.length - offset, len - (data.length - offset));
|
||||||
|
str = new String(bytes);
|
||||||
|
}
|
||||||
|
pop(len);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resize() {
|
||||||
|
byte[] newData = new byte[data.length * 2];
|
||||||
|
System.arraycopy(data, 0, newData, 0, data.length);
|
||||||
|
data = newData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SocketReader implements Runnable {
|
||||||
|
|
||||||
private final Socket mSocket;
|
private final Socket mSocket;
|
||||||
private final InputStream mInputStream;
|
private final InputStream mInputStream;
|
||||||
private ByteBuffer mByteBuffer;
|
|
||||||
private int mJsonDataLength = -1;
|
private int mJsonDataLength = -1;
|
||||||
private int mReceivedDataLength = 0;
|
private ByteQueue mByteQueue = new ByteQueue(4096);
|
||||||
private byte[] mBuffer;
|
|
||||||
|
|
||||||
private SocketReader(Socket socket) throws IOException {
|
private SocketReader(Socket socket) throws IOException {
|
||||||
mSocket = socket;
|
mSocket = socket;
|
||||||
mInputStream = mSocket.getInputStream();
|
mInputStream = mSocket.getInputStream();
|
||||||
mByteBuffer = ByteBuffer.allocateDirect(3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
readLoop();
|
readLoop();
|
||||||
|
close();
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
} finally {
|
close(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readLoop() throws IOException {
|
|
||||||
byte[] buffer = new byte[4096];
|
private void readLoop() throws Exception {
|
||||||
int n;
|
int n;
|
||||||
while ((n = mInputStream.read(buffer)) > 0) {
|
while ((n = mByteQueue.read(mInputStream)) > 0) {
|
||||||
onChunk(buffer, 0, n);
|
onChunk(mByteQueue, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onChunk(byte[] data, int offset, int length) {
|
private void onChunk(ByteQueue byteQueue, int chunkSize) {
|
||||||
if(mJsonDataLength != 0){
|
if (mJsonDataLength <= 0) {
|
||||||
|
tryReadingJsonDataLength(byteQueue, chunkSize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (byteQueue.length < mJsonDataLength) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String json = byteQueue.popAsString(mJsonDataLength);
|
||||||
|
Log.d(LOG_TAG, "json = " + json);
|
||||||
|
mJsonDataLength = -1;
|
||||||
|
dispatchJson(json);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void tryReadingJsonDataLength(ByteQueue byteQueue, int chunkSize) {
|
||||||
|
int end = byteQueue.offset + byteQueue.length;
|
||||||
|
for (int i = 1; i <= chunkSize; i++) {
|
||||||
|
if (byteQueue.data[end - i] == DELIMITER) {
|
||||||
|
String jsonDataLength = new String(byteQueue.data, byteQueue.offset, end - i);
|
||||||
|
Log.d(LOG_TAG, "json data length = " + jsonDataLength);
|
||||||
|
byteQueue.pop(end - i + 1);
|
||||||
|
receiveJsonDataLength(jsonDataLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void receiveJsonDataLength(String jsonDataLength) {
|
||||||
|
try {
|
||||||
|
mJsonDataLength = Integer.parseInt(jsonDataLength);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package org.autojs.autojs.pluginclient;
|
package org.autojs.autojs.pluginclient;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -11,13 +14,18 @@ import java.util.Map;
|
|||||||
|
|
||||||
public class Router implements Handler {
|
public class Router implements Handler {
|
||||||
|
|
||||||
private Map<String, Handler> mHandlerMap = new HashMap<>();
|
private static final String LOG_TAG = "Router";
|
||||||
private String mKey;
|
protected Map<String, Handler> mHandlerMap = new HashMap<>();
|
||||||
|
private final String mKey;
|
||||||
|
|
||||||
public Router(String key) {
|
public Router(String key) {
|
||||||
mKey = key;
|
mKey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
return mKey;
|
||||||
|
}
|
||||||
|
|
||||||
public Router handler(String value, Handler handler) {
|
public Router handler(String value, Handler handler) {
|
||||||
mHandlerMap.put(value, handler);
|
mHandlerMap.put(value, handler);
|
||||||
return this;
|
return this;
|
||||||
@@ -25,8 +33,35 @@ public class Router implements Handler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handle(JsonObject data) {
|
public boolean handle(JsonObject data) {
|
||||||
Handler handler = mHandlerMap.get(data.get(mKey).getAsString());
|
Log.d(LOG_TAG, "handle: " + data);
|
||||||
return handler != null && handler.handle(data);
|
JsonElement key = data.get(getKey());
|
||||||
|
if (key == null || !key.isJsonPrimitive()) {
|
||||||
|
Log.w(LOG_TAG, "no such key: " + getKey());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Handler handler = mHandlerMap.get(key.getAsString());
|
||||||
|
return handleInternal(data, key.getAsString(), handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean handleInternal(JsonObject json, String key, Handler handler) {
|
||||||
|
return handler != null && handler.handle(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RootRouter extends Router {
|
||||||
|
|
||||||
|
public RootRouter(String key) {
|
||||||
|
super(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean handleInternal(JsonObject json, String key, Handler handler) {
|
||||||
|
JsonElement data = json.get("data");
|
||||||
|
if (data == null || !data.isJsonObject()) {
|
||||||
|
Log.w(LOG_TAG, "json has no object data: " + json);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return handler != null && handler.handle(data.getAsJsonObject());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
15
app/src/main/java/org/autojs/autojs/tool/EmptyObservers.java
Normal file
15
app/src/main/java/org/autojs/autojs/tool/EmptyObservers.java
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package org.autojs.autojs.tool;
|
||||||
|
|
||||||
|
import io.reactivex.functions.Consumer;
|
||||||
|
|
||||||
|
public class EmptyObservers {
|
||||||
|
|
||||||
|
private static final Consumer CONSUMER = ignored -> {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> Consumer<T> consumer() {
|
||||||
|
return CONSUMER;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,11 +19,12 @@ import com.bumptech.glide.request.target.SimpleTarget;
|
|||||||
import com.bumptech.glide.request.transition.Transition;
|
import com.bumptech.glide.request.transition.Transition;
|
||||||
import com.stardust.app.GlobalAppContext;
|
import com.stardust.app.GlobalAppContext;
|
||||||
import com.stardust.notification.NotificationListenerService;
|
import com.stardust.notification.NotificationListenerService;
|
||||||
|
|
||||||
import org.autojs.autojs.Pref;
|
import org.autojs.autojs.Pref;
|
||||||
import org.autojs.autojs.R;
|
import org.autojs.autojs.R;
|
||||||
import org.autojs.autojs.network.GlideApp;
|
import org.autojs.autojs.network.GlideApp;
|
||||||
import org.autojs.autojs.network.UserService;
|
import org.autojs.autojs.network.UserService;
|
||||||
import org.autojs.autojs.pluginclient.DevPluginClient;
|
import org.autojs.autojs.tool.EmptyObservers;
|
||||||
import org.autojs.autojs.ui.common.NotAskAgainDialog;
|
import org.autojs.autojs.ui.common.NotAskAgainDialog;
|
||||||
import org.autojs.autojs.ui.floating.CircularMenu;
|
import org.autojs.autojs.ui.floating.CircularMenu;
|
||||||
import org.autojs.autojs.ui.floating.FloatyWindowManger;
|
import org.autojs.autojs.ui.floating.FloatyWindowManger;
|
||||||
@@ -41,12 +42,17 @@ import org.autojs.autojs.ui.update.UpdateInfoDialogBuilder;
|
|||||||
import org.autojs.autojs.ui.user.WebActivity;
|
import org.autojs.autojs.ui.user.WebActivity;
|
||||||
import org.autojs.autojs.ui.user.WebActivity_;
|
import org.autojs.autojs.ui.user.WebActivity_;
|
||||||
import org.autojs.autojs.ui.widget.AvatarView;
|
import org.autojs.autojs.ui.widget.AvatarView;
|
||||||
|
|
||||||
import com.stardust.theme.ThemeColorManager;
|
import com.stardust.theme.ThemeColorManager;
|
||||||
|
|
||||||
import org.autojs.autojs.theme.ThemeColorManagerCompat;
|
import org.autojs.autojs.theme.ThemeColorManagerCompat;
|
||||||
|
|
||||||
import com.stardust.view.accessibility.AccessibilityService;
|
import com.stardust.view.accessibility.AccessibilityService;
|
||||||
|
|
||||||
import org.autojs.autojs.pluginclient.DevPluginService;
|
import org.autojs.autojs.pluginclient.DevPluginService;
|
||||||
import org.autojs.autojs.tool.AccessibilityServiceTool;
|
import org.autojs.autojs.tool.AccessibilityServiceTool;
|
||||||
import org.autojs.autojs.tool.WifiTool;
|
import org.autojs.autojs.tool.WifiTool;
|
||||||
|
|
||||||
import com.stardust.util.IntentUtil;
|
import com.stardust.util.IntentUtil;
|
||||||
|
|
||||||
import org.androidannotations.annotations.AfterViews;
|
import org.androidannotations.annotations.AfterViews;
|
||||||
@@ -112,12 +118,12 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
mConnectionStateDisposable = DevPluginService.getInstance().getConnection()
|
mConnectionStateDisposable = DevPluginService.getInstance().connectionState()
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(state -> {
|
.subscribe(state -> {
|
||||||
if (mConnectionItem != null) {
|
if (mConnectionItem != null) {
|
||||||
setChecked(mConnectionItem, state.getState() == DevPluginClient.State.CONNECTED);
|
setChecked(mConnectionItem, state.getState() == DevPluginService.State.CONNECTED);
|
||||||
setProgress(mConnectionItem, state.getState() == DevPluginClient.State.CONNECTING);
|
setProgress(mConnectionItem, state.getState() == DevPluginService.State.CONNECTING);
|
||||||
}
|
}
|
||||||
if (state.getException() != null) {
|
if (state.getException() != null) {
|
||||||
showMessage(state.getException().getMessage());
|
showMessage(state.getException().getMessage());
|
||||||
@@ -251,7 +257,8 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
|
|||||||
.title(R.string.text_server_address)
|
.title(R.string.text_server_address)
|
||||||
.input("", host, (dialog, input) -> {
|
.input("", host, (dialog, input) -> {
|
||||||
Pref.saveServerAddress(input.toString());
|
Pref.saveServerAddress(input.toString());
|
||||||
DevPluginService.getInstance().connectToServer(input.toString());
|
DevPluginService.getInstance().connectToServer(input.toString())
|
||||||
|
.subscribe(EmptyObservers.consumer(), this::onConnectException);
|
||||||
})
|
})
|
||||||
.neutralText(R.string.text_help)
|
.neutralText(R.string.text_help)
|
||||||
.onNeutral((dialog, which) -> {
|
.onNeutral((dialog, which) -> {
|
||||||
@@ -262,6 +269,13 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onConnectException(Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
setChecked(mConnectionItem, false);
|
||||||
|
Toast.makeText(GlobalAppContext.get(), getString(R.string.error_connect_to_remote, e.getMessage()),
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
void checkForUpdates(DrawerMenuItemViewHolder holder) {
|
void checkForUpdates(DrawerMenuItemViewHolder holder) {
|
||||||
setProgress(mCheckForUpdatesItem, true);
|
setProgress(mCheckForUpdatesItem, true);
|
||||||
VersionService.getInstance().checkForUpdates()
|
VersionService.getInstance().checkForUpdates()
|
||||||
|
|||||||
@@ -380,4 +380,5 @@
|
|||||||
<string name="text_close">关闭</string>
|
<string name="text_close">关闭</string>
|
||||||
<string name="text_execute">执行</string>
|
<string name="text_execute">执行</string>
|
||||||
<string name="text_use_alarm_clock">使用系统闹钟唤醒Auto.js</string>
|
<string name="text_use_alarm_clock">使用系统闹钟唤醒Auto.js</string>
|
||||||
|
<string name="error_connect_to_remote">连接失败: %s</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user