diff options
Diffstat (limited to 'src/main/java/moe/nea')
-rw-r--r-- | src/main/java/moe/nea/wayfiresocket/Main.java | 13 | ||||
-rw-r--r-- | src/main/java/moe/nea/wayfiresocket/Ping.java | 16 | ||||
-rw-r--r-- | src/main/java/moe/nea/wayfiresocket/Request.java | 7 | ||||
-rw-r--r-- | src/main/java/moe/nea/wayfiresocket/Run.java | 16 | ||||
-rw-r--r-- | src/main/java/moe/nea/wayfiresocket/WayfireSocket.java | 87 |
5 files changed, 139 insertions, 0 deletions
diff --git a/src/main/java/moe/nea/wayfiresocket/Main.java b/src/main/java/moe/nea/wayfiresocket/Main.java new file mode 100644 index 0000000..1c81604 --- /dev/null +++ b/src/main/java/moe/nea/wayfiresocket/Main.java @@ -0,0 +1,13 @@ +package moe.nea.wayfiresocket; + +import java.nio.file.Path; + +public class Main { + public static void main(String[] args) throws Exception { + try (var socket = new WayfireSocket(Path.of("/tmp/wayfire-wayland-2.socket"))) { + System.out.println(socket.callMethod(new Ping())); + Run.Response response = socket.callMethod(new Run("/bin/echo")); + var pid = response.pid(); + } + } +} diff --git a/src/main/java/moe/nea/wayfiresocket/Ping.java b/src/main/java/moe/nea/wayfiresocket/Ping.java new file mode 100644 index 0000000..d47d618 --- /dev/null +++ b/src/main/java/moe/nea/wayfiresocket/Ping.java @@ -0,0 +1,16 @@ +package moe.nea.wayfiresocket; + +public record Ping() implements Request<Ping.Response> { + @Override + public Class<Response> getResponseType() { + return Response.class; + } + + @Override + public String getMethodName() { + return "stipc/ping"; + } + + public record Response(String result) {} + +} diff --git a/src/main/java/moe/nea/wayfiresocket/Request.java b/src/main/java/moe/nea/wayfiresocket/Request.java new file mode 100644 index 0000000..8b7efc9 --- /dev/null +++ b/src/main/java/moe/nea/wayfiresocket/Request.java @@ -0,0 +1,7 @@ +package moe.nea.wayfiresocket; + +public interface Request<ResponseType> { + Class<ResponseType> getResponseType(); + + String getMethodName(); +} diff --git a/src/main/java/moe/nea/wayfiresocket/Run.java b/src/main/java/moe/nea/wayfiresocket/Run.java new file mode 100644 index 0000000..07e546b --- /dev/null +++ b/src/main/java/moe/nea/wayfiresocket/Run.java @@ -0,0 +1,16 @@ +package moe.nea.wayfiresocket; + +public record Run(String cmd) implements Request<Run.Response> { + + @Override + public Class<Response> getResponseType() { + return Response.class; + } + + @Override + public String getMethodName() { + return "stipc/run"; + } + + public record Response(int pid) {} +} diff --git a/src/main/java/moe/nea/wayfiresocket/WayfireSocket.java b/src/main/java/moe/nea/wayfiresocket/WayfireSocket.java new file mode 100644 index 0000000..5afb77a --- /dev/null +++ b/src/main/java/moe/nea/wayfiresocket/WayfireSocket.java @@ -0,0 +1,87 @@ +package moe.nea.wayfiresocket; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import java.io.Closeable; +import java.io.IOException; +import java.net.UnixDomainSocketAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.SocketChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; + +public class WayfireSocket implements Closeable { + private static final Gson gson = new Gson(); + private final SocketChannel channel; + private ByteBuffer writeBuf; + + public WayfireSocket(Path path) throws IOException { + this.channel = SocketChannel.open(UnixDomainSocketAddress.of(path)); + } + + private static JsonObject makeCallObject(String method, JsonElement data) { + var obj = new JsonObject(); + obj.addProperty("method", method); + obj.add("data", data); + return obj; + } + + public static void require(boolean fact, String error) { + if (!fact) throw new RuntimeException(error); + // This variable was fact checked by true dark nea acolytes + } + + public JsonObject readMessage() throws IOException { + return gson.fromJson(readMessageString(), JsonObject.class); + } + + public <R, T extends Request<R>> R callMethod(T object) throws IOException { + var json = callMethod(object.getMethodName(), gson.toJsonTree(object)); + return gson.fromJson(json, object.getResponseType()); + } + + public JsonObject callMethod(String method, JsonElement data) throws IOException { + writeMessage(makeCallObject(method, data)); + return readMessage(); + } + + private String readMessageString() throws IOException { + var buf = allocWriteBuf(4); + require(channel.read(buf) == 4, "Could not read message size"); + var readLength = buf.flip().getInt(); + buf = allocWriteBuf(readLength); + channel.read(buf); + byte[] bytes = new byte[readLength]; + buf.flip().get(bytes); + return new String(bytes, StandardCharsets.UTF_8); + } + + public void writeMessage(JsonObject object) throws IOException { + writeMessage(gson.toJson(object)); + } + + private ByteBuffer allocWriteBuf(int length) { + if (writeBuf == null || writeBuf.capacity() < length) { + writeBuf = ByteBuffer.allocate(length) + .order(ByteOrder.LITTLE_ENDIAN); + } + return writeBuf.clear().limit(length); + } + + private void writeMessage(String json) throws IOException { + var bytes = json.getBytes(StandardCharsets.UTF_8); + var buffer = allocWriteBuf(bytes.length + 4); + buffer.putInt(bytes.length); + buffer.put(bytes); + buffer.flip(); + require(channel.write(buffer) == bytes.length + 4, "Could not write entire message"); + } + + @Override + public void close() throws IOException { + channel.close(); + } +} |