diff --git a/android/src/main/java/software/eskimo/capacitor/sockets/SocketConnection.java b/android/src/main/java/software/eskimo/capacitor/sockets/SocketConnection.java deleted file mode 100644 index 34114f1..0000000 --- a/android/src/main/java/software/eskimo/capacitor/sockets/SocketConnection.java +++ /dev/null @@ -1,138 +0,0 @@ -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/SocketHandler.java b/android/src/main/java/software/eskimo/capacitor/sockets/SocketHandler.java new file mode 100644 index 0000000..6351607 --- /dev/null +++ b/android/src/main/java/software/eskimo/capacitor/sockets/SocketHandler.java @@ -0,0 +1,122 @@ +package software.eskimo.capacitor.sockets; + +import android.util.Log; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.Socket; +import java.security.NoSuchAlgorithmException; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import java.io.IOException; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.cert.X509Certificate; + +public class SocketHandler { + private String id; + private Socket socket; + private OutputStream outputStream; + private BufferedReader inputStream; + private SocketDelegate delegate; + + public SocketHandler(String id, SocketDelegate delegate) { + this.id = id; + this.delegate = delegate; + } + + public String getId() { + return id; + } + + public void connect(final String host, final int port, final boolean useTLS, final boolean acceptInvalidCertificates) { + new Thread(() -> { + try { + if (useTLS) { + SSLContext sslContext = SSLContext.getInstance("TLS"); + if (acceptInvalidCertificates) { + sslContext.init(null, new TrustManager[]{new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) {} + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) {} + + @Override + public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } + }}, new java.security.SecureRandom()); + } else { + sslContext.init(null, null, new java.security.SecureRandom()); + } + SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + socket = socketFactory.createSocket(host, port); + } else { + socket = new Socket(host, port); + } + delegate.onStateChanged(id, "connected"); + outputStream = socket.getOutputStream(); + inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream())); + receive(); + } catch (Exception e) { + Log.e("SocketHandler", "Connection error: " + e.getMessage(), e); + delegate.onStateChanged(id, "disconnected"); + } + }).start(); + } + + public void send(String message) { + new Thread(() -> { + try { + if (outputStream != null) { + outputStream.write(message.getBytes()); + outputStream.flush(); + } + } catch (IOException e) { + Log.e("SocketHandler", "Send error: " + e.getMessage(), e); + delegate.onStateChanged(id, "disconnected"); + } + }).start(); + } + + public void disconnect() { + try { + if (socket != null) { + socket.close(); + } + delegate.onStateChanged(id, "disconnected"); + } catch (IOException e) { + Log.e("SocketHandler", "Disconnect error: " + e.getMessage(), e); + delegate.onStateChanged(id, "disconnected"); + } + } + + private void receive() { + new Thread(() -> { + try { + char[] buffer = new char[1024]; + StringBuilder messageBuilder = new StringBuilder(); + int numCharsRead; + while ((numCharsRead = inputStream.read(buffer)) != -1) { + messageBuilder.append(buffer, 0, numCharsRead); + String message = messageBuilder.toString(); + + // Check if the message ends with \r\n (or \n, depending on protocol) + if (message.endsWith("\r\n")) { + Log.d("SocketHandler", "Message received: " + message); + delegate.onMessageReceived(id, message); // Notify with full message including \r\n + messageBuilder.setLength(0); // Clear the buffer for the next message + } + } + } catch (IOException e) { + Log.e("SocketHandler", "Receive error: " + e.getMessage(), e); + delegate.onStateChanged(id, "disconnected"); + } + }).start(); +} + + + public interface SocketDelegate { + void onStateChanged(String socketId, String state); + void onMessageReceived(String socketId, String message); + } +} 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 ad303d8..09d2544 100644 --- a/android/src/main/java/software/eskimo/capacitor/sockets/Sockets.java +++ b/android/src/main/java/software/eskimo/capacitor/sockets/Sockets.java @@ -4,57 +4,64 @@ import android.util.Log; import java.util.ArrayList; import java.util.List; -public class Sockets implements SocketDelegate { +public class Sockets implements SocketHandler.SocketDelegate { - private List sockets = new ArrayList<>(); - private SocketsPlugin plugin; + private List sockets = new ArrayList<>(); + private SocketsPlugin plugin; // Reference to SocketsPlugin for notifying JS public Sockets(SocketsPlugin plugin) { - this.plugin = plugin; + this.plugin = plugin; // Pass plugin reference for message forwarding } - @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); + public SocketHandler create(String id) { + SocketHandler socket = new SocketHandler(id, 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 connect(String id, String host, int port, boolean useTLS, boolean acceptInvalidCertificates) { + SocketHandler socket = getSocketById(id); + if (socket != null) { + socket.connect(host, port, useTLS, acceptInvalidCertificates); } } public void send(String id, String message) { - for (SocketConnection socket : sockets) { - if (socket.id.equals(id)) { - socket.send(message); - break; - } + SocketHandler socket = getSocketById(id); + if (socket != null) { + socket.send(message); } } public void disconnect(String id) { - for (SocketConnection socket : sockets) { - if (socket.id.equals(id)) { - socket.disconnect(); - break; - } + SocketHandler socket = getSocketById(id); + if (socket != null) { + socket.disconnect(); } } + + private SocketHandler getSocketById(String id) { + for (SocketHandler socket : sockets) { + if (socket.getId().equals(id)) { + return socket; + } + } + return null; + } + + // Handle state changes (connected, disconnected) + @Override + public void onStateChanged(String socketId, String state) { + Log.d("Sockets", "Socket state changed: " + state); + // Call notifyStateListeners in SocketsPlugin + plugin.notifyStateListeners("state", socketId, state); + } + + // Handle incoming messages + @Override + public void onMessageReceived(String socketId, String message) { + Log.d("Sockets", "Socket message received: " + message); + // Call notifyMessageListeners in SocketsPlugin + plugin.notifyMessageListeners(socketId, message); // Notify JS about the received message + } } 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 df07c91..ba1d3de 100644 --- a/android/src/main/java/software/eskimo/capacitor/sockets/SocketsPlugin.java +++ b/android/src/main/java/software/eskimo/capacitor/sockets/SocketsPlugin.java @@ -4,67 +4,65 @@ import android.util.Log; import com.getcapacitor.JSObject; import com.getcapacitor.Plugin; import com.getcapacitor.PluginCall; -import com.getcapacitor.PluginMethod; import com.getcapacitor.annotation.CapacitorPlugin; +import com.getcapacitor.PluginMethod; @CapacitorPlugin(name = "Sockets") public class SocketsPlugin extends Plugin { - 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); - } + private Sockets implementation = new Sockets(this); // Pass the plugin reference @PluginMethod 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); - - implementation.create(id, host, port, useTLS, acceptInvalidCertificates); + implementation.create(id); call.resolve(); } @PluginMethod public void connect(PluginCall call) { - String id = call.getString("id"); - implementation.connect(id); + String id = call.getString("id", ""); + String host = call.getString("host", ""); + int port = call.getInt("port", 0); + boolean useTLS = call.getBoolean("useTLS", false); + boolean acceptInvalidCertificates = call.getBoolean("acceptInvalidCertificates", false); + + implementation.connect(id, host, port, useTLS, acceptInvalidCertificates); call.resolve(); } @PluginMethod public void send(PluginCall call) { - String id = call.getString("id"); - String message = call.getString("message"); + 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"); + String id = call.getString("id", ""); + implementation.disconnect(id); call.resolve(); } -} \ No newline at end of file + + // Helper method for notifying JavaScript listeners about state changes + public void notifyStateListeners(String event, String id, String state) { + JSObject data = new JSObject(); + data.put("id", id); + data.put("state", state); + notifyListeners(event, data); + } + + public void notifyMessageListeners(String id, String message) { + JSObject data = new JSObject(); + data.put("id", id); + data.put("message", message); // Include the message content + + Log.d("SocketsPlugin", "Message to JS: " + data.toString()); // Log the data being sent to JS + + notifyListeners("message", data); // Notify JS listeners of the 'message' event + } +}