From 49989b0e582998bad8dc0e5611dc2b4c2db25d73 Mon Sep 17 00:00:00 2001 From: eskimo Date: Thu, 3 Oct 2024 14:42:36 -0400 Subject: [PATCH] i broke it :) --- README.md | 16 +- .../capacitor/sockets/SocketConnection.java | 138 ++++++++++++++++++ .../eskimo/capacitor/sockets/Sockets.java | 57 +++++++- .../capacitor/sockets/SocketsPlugin.java | 62 +++++++- ios/Sources/SocketsPlugin/Socket.swift | 19 +-- ios/Sources/SocketsPlugin/Sockets.swift | 8 +- ios/Sources/SocketsPlugin/SocketsPlugin.swift | 14 +- src/definitions.ts | 4 +- src/socket.ts | 24 +-- 9 files changed, 279 insertions(+), 63 deletions(-) create mode 100644 android/src/main/java/software/eskimo/capacitor/sockets/SocketConnection.java diff --git a/README.md b/README.md index 2d9e0ce..f55eef3 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,12 @@ npx cap sync ### create(...) ```typescript -create(options: { id: string; host: string; port: number; useTLS?: boolean; acceptInvalidCertificates?: boolean; }) => Promise +create(options: { id: string; }) => Promise ``` -| Param | Type | -| ------------- | --------------------------------------------------------------------------------------------------------------- | -| **`options`** | { id: string; host: string; port: number; useTLS?: boolean; acceptInvalidCertificates?: boolean; } | +| Param | Type | +| ------------- | ---------------------------- | +| **`options`** | { id: string; } | -------------------- @@ -43,12 +43,12 @@ create(options: { id: string; host: string; port: number; useTLS?: boolean; acce ### connect(...) ```typescript -connect(options: { id: string; }) => Promise +connect(options: { id: string; host: string; port: number; useTLS?: boolean; acceptInvalidCertificates?: boolean; }) => Promise ``` -| Param | Type | -| ------------- | ---------------------------- | -| **`options`** | { id: string; } | +| Param | Type | +| ------------- | --------------------------------------------------------------------------------------------------------------- | +| **`options`** | { id: string; host: string; port: number; useTLS?: boolean; acceptInvalidCertificates?: boolean; } | -------------------- diff --git a/android/src/main/java/software/eskimo/capacitor/sockets/SocketConnection.java b/android/src/main/java/software/eskimo/capacitor/sockets/SocketConnection.java new file mode 100644 index 0000000..34114f1 --- /dev/null +++ b/android/src/main/java/software/eskimo/capacitor/sockets/SocketConnection.java @@ -0,0 +1,138 @@ +package software.eskimo.capacitor.sockets; + +import android.os.Handler; +import android.os.Looper; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.Socket; +import java.net.InetSocketAddress; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import javax.net.ssl.SSLContext; + +interface SocketDelegate { + void didChangeState(String socketId, String state); + void didReceiveMessage(String socketId, String message); +} + +public class SocketConnection { + + public String id; + private String host; + private int port; + private boolean useTLS; + private boolean acceptInvalidCertificates; + private SocketDelegate delegate; + + private Socket socket; + private ExecutorService executor; + + public SocketConnection(String id, String host, int port, boolean useTLS, boolean acceptInvalidCertificates) { + this.id = id; + this.host = host; + this.port = port; + this.useTLS = useTLS; + this.acceptInvalidCertificates = acceptInvalidCertificates; + this.executor = Executors.newSingleThreadExecutor(); + } + + public void setDelegate(SocketDelegate delegate) { + this.delegate = delegate; + } + + public void connect() { + executor.execute(() -> { + try { + if (useTLS) { + SSLSocketFactory factory; + if (acceptInvalidCertificates) { + SSLContext sslContext = SSLContext.getInstance("TLS"); + TrustManager[] trustManagers = new TrustManager[]{ + new X509TrustManager() { + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { + } + } + }; + sslContext.init(null, trustManagers, new java.security.SecureRandom()); + factory = sslContext.getSocketFactory(); + } else { + factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); + } + socket = factory.createSocket(); + socket.connect(new InetSocketAddress(host, port)); + delegate.didChangeState(id, "connected"); + } else { + socket = new Socket(); + socket.connect(new InetSocketAddress(host, port)); + delegate.didChangeState(id, "connected"); + } + + listenForMessages(); + } catch (Exception e) { + e.printStackTrace(); + delegate.didChangeState(id, "disconnected"); + } + }); + } + + public void send(String message) { + executor.execute(() -> { + try { + if (socket != null && socket.isConnected()) { + OutputStream outputStream = socket.getOutputStream(); + outputStream.write(message.getBytes()); + outputStream.flush(); + } + } catch (Exception e) { + e.printStackTrace(); + } + }); + } + + public void disconnect() { + try { + if (socket != null && !socket.isClosed()) { + socket.close(); + delegate.didChangeState(id, "disconnected"); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void listenForMessages() { + executor.execute(() -> { + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); + char[] buffer = new char[1024]; // Adjust buffer size as needed + int charsRead; + + while ((charsRead = reader.read(buffer)) != -1) { + String message = new String(buffer, 0, charsRead); + delegate.didReceiveMessage(id, message); + } + } catch (Exception e) { + e.printStackTrace(); + disconnect(); + } + }); + } + +} diff --git a/android/src/main/java/software/eskimo/capacitor/sockets/Sockets.java b/android/src/main/java/software/eskimo/capacitor/sockets/Sockets.java index 33ef707..ad303d8 100644 --- a/android/src/main/java/software/eskimo/capacitor/sockets/Sockets.java +++ b/android/src/main/java/software/eskimo/capacitor/sockets/Sockets.java @@ -1,11 +1,60 @@ package software.eskimo.capacitor.sockets; import android.util.Log; +import java.util.ArrayList; +import java.util.List; -public class Sockets { +public class Sockets implements SocketDelegate { - public String echo(String value) { - Log.i("Echo", value); - return value; + private List sockets = new ArrayList<>(); + private SocketsPlugin plugin; + + public Sockets(SocketsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void didChangeState(String socketId, String state) { + plugin.notifyStateChange(socketId, state); + } + + @Override + public void didReceiveMessage(String socketId, String message) { + Log.e("Sockets", "Received message: " + message); + plugin.notifyMessageReceived(socketId, message); + } + + public SocketConnection create(String id, String host, int port, boolean useTLS, boolean acceptInvalidCertificates) { + SocketConnection socket = new SocketConnection(id, host, port, useTLS, acceptInvalidCertificates); + socket.setDelegate(this); + sockets.add(socket); + return socket; + } + + public void connect(String id) { + for (SocketConnection socket : sockets) { + if (socket.id.equals(id)) { + socket.connect(); + break; + } + } + } + + public void send(String id, String message) { + for (SocketConnection socket : sockets) { + if (socket.id.equals(id)) { + socket.send(message); + break; + } + } + } + + public void disconnect(String id) { + for (SocketConnection socket : sockets) { + if (socket.id.equals(id)) { + socket.disconnect(); + break; + } + } } } diff --git a/android/src/main/java/software/eskimo/capacitor/sockets/SocketsPlugin.java b/android/src/main/java/software/eskimo/capacitor/sockets/SocketsPlugin.java index a76bb21..df07c91 100644 --- a/android/src/main/java/software/eskimo/capacitor/sockets/SocketsPlugin.java +++ b/android/src/main/java/software/eskimo/capacitor/sockets/SocketsPlugin.java @@ -1,5 +1,6 @@ package software.eskimo.capacitor.sockets; +import android.util.Log; import com.getcapacitor.JSObject; import com.getcapacitor.Plugin; import com.getcapacitor.PluginCall; @@ -9,14 +10,61 @@ import com.getcapacitor.annotation.CapacitorPlugin; @CapacitorPlugin(name = "Sockets") public class SocketsPlugin extends Plugin { - private Sockets implementation = new Sockets(); + private Sockets implementation; + + @Override + public void load() { + implementation = new Sockets(this); + } + + public void notifyStateChange(String socketId, String state) { + JSObject data = new JSObject(); + data.put("id", socketId); + data.put("state", state); + notifyListeners("state", data); + } + + public void notifyMessageReceived(String socketId, String message) { + JSObject data = new JSObject(); + data.put("id", socketId); + data.put("message", message); + + Log.e("SocketsPlugin", "Received message: " + message); + + notifyListeners("message", data); + } @PluginMethod - public void echo(PluginCall call) { - String value = call.getString("value"); + public void create(PluginCall call) { + String id = call.getString("id", java.util.UUID.randomUUID().toString()); + String host = call.getString("host"); + int port = call.getInt("port"); + boolean useTLS = call.getBoolean("useTLS", false); + boolean acceptInvalidCertificates = call.getBoolean("acceptInvalidCertificates", false); - JSObject ret = new JSObject(); - ret.put("value", implementation.echo(value)); - call.resolve(ret); + implementation.create(id, host, port, useTLS, acceptInvalidCertificates); + call.resolve(); } -} + + @PluginMethod + public void connect(PluginCall call) { + String id = call.getString("id"); + implementation.connect(id); + call.resolve(); + } + + @PluginMethod + public void send(PluginCall call) { + String id = call.getString("id"); + String message = call.getString("message"); + implementation.send(id, message); + call.resolve(); + } + + @PluginMethod + public void disconnect(PluginCall call) { + String id = call.getString("id"); + implementation.disconnect(id); + call.resolve(); + } +} \ No newline at end of file diff --git a/ios/Sources/SocketsPlugin/Socket.swift b/ios/Sources/SocketsPlugin/Socket.swift index a8335d6..9ecbf03 100644 --- a/ios/Sources/SocketsPlugin/Socket.swift +++ b/ios/Sources/SocketsPlugin/Socket.swift @@ -9,30 +9,21 @@ protocol SocketDelegate: AnyObject { public class Socket: NSObject { var id: String - var host: String - var port: Int - var useTLS: Bool - var acceptInvalidCertificates: Bool var connection: NWConnection? weak var delegate: SocketDelegate? - public init(id: String, host: String, port: Int, useTLS: Bool, acceptInvalidCertificates: Bool) { + public init(id: String) { self.id = id - self.host = host - self.port = port - - self.useTLS = useTLS - self.acceptInvalidCertificates = acceptInvalidCertificates } - public func connect() { + public func connect(host: String, port: Int, useTLS: Bool, acceptInvalidCertificates: Bool) { let parameters = NWParameters.tcp - if self.useTLS { + if useTLS { let tls = NWProtocolTLS.Options() - if (self.acceptInvalidCertificates) { + if (acceptInvalidCertificates) { sec_protocol_options_set_verify_block(tls.securityProtocolOptions, { (sec_protocol_metadata, sec_trust, sec_protocol_verify_complete) in sec_protocol_verify_complete(true) }, DispatchQueue.global()) @@ -41,7 +32,7 @@ public class Socket: NSObject { parameters.defaultProtocolStack.applicationProtocols.insert(tls, at: 0) } - let connection = NWConnection(host: NWEndpoint.Host(self.host), port: NWEndpoint.Port(String(self.port))!, using: parameters) + let connection = NWConnection(host: NWEndpoint.Host(host), port: NWEndpoint.Port(String(port))!, using: parameters) connection.stateUpdateHandler = self.stateDidChange(to:) self.receive(on: connection) connection.start(queue: .main) diff --git a/ios/Sources/SocketsPlugin/Sockets.swift b/ios/Sources/SocketsPlugin/Sockets.swift index 51f8efb..a050698 100644 --- a/ios/Sources/SocketsPlugin/Sockets.swift +++ b/ios/Sources/SocketsPlugin/Sockets.swift @@ -29,16 +29,16 @@ enum SocketState:String { ]) } - @objc public func create(id: String, host: String, port: Int, useTLS: Bool = false, acceptInvalidCertificates: Bool = false) -> Socket { - let socket = Socket(id: id, host: host, port: port, useTLS: useTLS, acceptInvalidCertificates: acceptInvalidCertificates) + @objc public func create(id: String) -> Socket { + let socket = Socket(id: id) socket.delegate = self sockets.append(socket) return socket } - @objc public func connect(id: String) { + @objc public func connect(id: String, host: String, port: Int, useTLS: Bool = false, acceptInvalidCertificates: Bool = false) { if let socket = self.socket(with: id) { - socket.connect() + socket.connect(host: host, port: port, useTLS: useTLS, acceptInvalidCertificates: acceptInvalidCertificates) } } diff --git a/ios/Sources/SocketsPlugin/SocketsPlugin.swift b/ios/Sources/SocketsPlugin/SocketsPlugin.swift index 9251e3f..420a541 100644 --- a/ios/Sources/SocketsPlugin/SocketsPlugin.swift +++ b/ios/Sources/SocketsPlugin/SocketsPlugin.swift @@ -19,19 +19,17 @@ public class SocketsPlugin: CAPPlugin, CAPBridgedPlugin { @objc func create(_ call: CAPPluginCall) { let id = call.getString("id") ?? UUID().uuidString - let host = call.getString("host") ?? "" - let port = call.getInt("port") ?? 0 - - let useTLS = call.getBool("useTLS") ?? false - let acceptInvalidCertificates = call.getBool("acceptInvalidCertificates") ?? false - - let socket = implementation.create(id: id, host: host, port: port, useTLS: useTLS, acceptInvalidCertificates: acceptInvalidCertificates) + let socket = implementation.create(id: id) call.resolve() } @objc func connect(_ call: CAPPluginCall) { let id = call.getString("id") ?? "" - implementation.connect(id: id) + let host = call.getString("host") ?? "" + let port = call.getInt("port") ?? 0 + let useTLS = call.getBool("useTLS") ?? false + let acceptInvalidCertificates = call.getBool("acceptInvalidCertificates") ?? false + implementation.connect(id: id, host: host, port: port, useTLS: useTLS, acceptInvalidCertificates: acceptInvalidCertificates) call.resolve() } diff --git a/src/definitions.ts b/src/definitions.ts index 13fcd26..5d424b6 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -1,8 +1,8 @@ import { PluginListenerHandle } from "@capacitor/core"; export interface SocketsPlugin { - create(options: { id: string; host: string; port: number, useTLS?: boolean, acceptInvalidCertificates?: boolean }): Promise; - connect(options: { id: string; }): Promise; + create(options: { id: string; }): Promise; + connect(options: { id: string; host: string; port: number, useTLS?: boolean, acceptInvalidCertificates?: boolean }): Promise; send(options: { id: string; message: string }): Promise; disconnect(options: { id: string }): Promise; close(options: { id: string }): Promise; diff --git a/src/socket.ts b/src/socket.ts index ac7fb9a..a3f31e6 100644 --- a/src/socket.ts +++ b/src/socket.ts @@ -51,21 +51,13 @@ class SocketManager { export default class Socket { id: string; - host: string; - port: number; - useTLS: boolean; - acceptInvalidCertificates: boolean; private emitter: Emitter; - constructor(config: { id: string; host: string; port: number; useTLS?: boolean; acceptInvalidCertificates?: boolean }) { + constructor(config: { id: string }) { console.log(config); this.id = config.id; - this.host = config.host; - this.port = config.port; - this.useTLS = config.useTLS ?? false; - this.acceptInvalidCertificates = config.acceptInvalidCertificates ?? false; this.emitter = mitt(); @@ -80,23 +72,23 @@ export default class Socket { create() { Sockets.create({ - id: this.id, - host: this.host, - port: this.port, - useTLS: this.useTLS, - acceptInvalidCertificates: this.acceptInvalidCertificates, + id: this.id }); } - connect() { + connect(config: { host: string; port: number; useTLS?: boolean; acceptInvalidCertificates?: boolean }) { Sockets.connect({ id: this.id, + host: config.host, + port: config.port, + useTLS: config.useTLS ?? false, + acceptInvalidCertificates: config.acceptInvalidCertificates ?? false }); } disconnect() { Sockets.disconnect({ - id: this.id, + id: this.id }); }