diff --git a/android/app/src/main/java/com/nostros/NostrosPackage.java b/android/app/src/main/java/com/nostros/NostrosPackage.java index adcdcef..ee32677 100644 --- a/android/app/src/main/java/com/nostros/NostrosPackage.java +++ b/android/app/src/main/java/com/nostros/NostrosPackage.java @@ -4,7 +4,7 @@ import com.facebook.react.ReactPackage; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.ViewManager; -import com.nostros.modules.WebsocketModule; +import com.nostros.modules.RelayPoolModule; import java.util.ArrayList; import java.util.Collections; @@ -21,7 +21,7 @@ public class NostrosPackage implements ReactPackage { ReactApplicationContext reactContext) { List modules = new ArrayList<>(); - modules.add(new WebsocketModule(reactContext)); + modules.add(new RelayPoolModule(reactContext)); return modules; } diff --git a/android/app/src/main/java/com/nostros/classes/Relay.java b/android/app/src/main/java/com/nostros/classes/Relay.java new file mode 100644 index 0000000..05815ca --- /dev/null +++ b/android/app/src/main/java/com/nostros/classes/Relay.java @@ -0,0 +1,45 @@ +package com.nostros.classes; + +import android.content.ContentValues; +import android.database.sqlite.SQLiteDatabase; +import android.util.Log; + +import com.nostros.modules.DatabaseModule; + +import java.io.IOException; + +public class Relay { + private Websocket webSocket; + public String url; + + public Relay(String serverUrl, DatabaseModule database) throws IOException { + webSocket = new Websocket(serverUrl, database); + url = serverUrl; + } + + public void send(String message) { + webSocket.send(message); + } + + public void disconnect() { + webSocket.disconnect(); + } + + public void connect(String userPubKey) throws IOException { + webSocket.connect(userPubKey); + } + + public void save(SQLiteDatabase database) { + ContentValues values = new ContentValues(); + values.put("url", url); + database.replace("nostros_relays", null, values); + } + + public void destroy(SQLiteDatabase database) { + String whereClause = "url = ?"; + String[] whereArgs = new String[] { + url + }; + database.delete ("nostros_relays", whereClause, whereArgs); + } +} diff --git a/android/app/src/main/java/com/nostros/modules/WebsocketModule.java b/android/app/src/main/java/com/nostros/classes/Websocket.java similarity index 61% rename from android/app/src/main/java/com/nostros/modules/WebsocketModule.java rename to android/app/src/main/java/com/nostros/classes/Websocket.java index dd66916..d2c3348 100644 --- a/android/app/src/main/java/com/nostros/modules/WebsocketModule.java +++ b/android/app/src/main/java/com/nostros/classes/Websocket.java @@ -1,58 +1,45 @@ -package com.nostros.modules; +package com.nostros.classes; import android.util.Log; -import com.facebook.react.bridge.Callback; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; import com.neovisionaries.ws.client.HostnameUnverifiedException; import com.neovisionaries.ws.client.OpeningHandshakeException; import com.neovisionaries.ws.client.WebSocket; import com.neovisionaries.ws.client.WebSocketAdapter; import com.neovisionaries.ws.client.WebSocketException; import com.neovisionaries.ws.client.WebSocketFactory; +import com.nostros.modules.DatabaseModule; import org.json.JSONArray; import java.io.IOException; -import java.util.List; -import java.util.Map; -public class WebsocketModule extends ReactContextBaseJavaModule { +public class Websocket { private WebSocket webSocket; private DatabaseModule database; - private String userPubKey; + private String url; - public WebsocketModule(ReactApplicationContext reactContext) { - super(reactContext); - database = new DatabaseModule(reactContext); + public Websocket(String serverUrl, DatabaseModule databaseModule) { + database = databaseModule; + url = serverUrl; } - @Override - public String getName() { - return "WebsocketModule"; - } - - @ReactMethod public void send(String message) { + Log.d("Websocket", "SEND URL:" + url + " __ " + message); webSocket.sendText(message); } - @ReactMethod - public void connectWebsocket(Callback callBack) throws IOException { + public void disconnect() { + webSocket.disconnect(); + } + + public void connect(String userPubKey) throws IOException { WebSocketFactory factory = new WebSocketFactory(); - webSocket = factory.createSocket("wss://relay.damus.io"); + webSocket = factory.createSocket(url); webSocket.addListener(new WebSocketAdapter() { - @Override - public void onConnected(WebSocket ws, Map> headers) throws Exception - { - callBack.invoke("connected"); - } - @Override public void onTextMessage(WebSocket websocket, String message) throws Exception { - Log.d("Websocket", message); + Log.d("Websocket", "RECEIVE URL:" + url + " __ " + message); JSONArray jsonArray = new JSONArray(message); if (jsonArray.get(0).toString().equals("EVENT")) { database.saveEvent(jsonArray.getJSONObject(2), userPubKey); @@ -77,9 +64,4 @@ public class WebsocketModule extends ReactContextBaseJavaModule { Log.d("WebSocket", "Failed to establish a WebSocket connection."); } } - - @ReactMethod - public void setUserPubKey(String userPubKey) { - this.userPubKey = userPubKey; - } } diff --git a/android/app/src/main/java/com/nostros/modules/DatabaseModule.java b/android/app/src/main/java/com/nostros/modules/DatabaseModule.java index 2e92ee4..2ac36fb 100644 --- a/android/app/src/main/java/com/nostros/modules/DatabaseModule.java +++ b/android/app/src/main/java/com/nostros/modules/DatabaseModule.java @@ -1,33 +1,57 @@ package com.nostros.modules; +import android.annotation.SuppressLint; +import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.util.Log; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; import com.nostros.classes.Event; +import com.nostros.classes.Relay; import org.json.JSONException; import org.json.JSONObject; -public class DatabaseModule extends ReactContextBaseJavaModule { +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class DatabaseModule { private SQLiteDatabase database; - DatabaseModule(ReactApplicationContext reactContext) { - super(reactContext); - String dbPath = reactContext.getFilesDir().getAbsolutePath(); - database = SQLiteDatabase.openDatabase( dbPath + "/nostros.sqlite", null, SQLiteDatabase.OPEN_READWRITE); + DatabaseModule(String absoluteFilesPath) { + database = SQLiteDatabase.openDatabase( absoluteFilesPath + "/nostros.sqlite", null, SQLiteDatabase.OPEN_READWRITE); } - @Override - public String getName() { - return "DatabaseModule"; - } - - @ReactMethod public void saveEvent(JSONObject data, String userPubKey) throws JSONException { Event event = new Event(data); event.save(database, userPubKey); } + + public void saveRelay(Relay relay) { + relay.save(database); + } + + public void destroyRelay(Relay relay) { + relay.destroy(database); + } + + public List getRelays() { + List relayList = new ArrayList<>(); + String query = "SELECT url FROM nostros_relays;"; + @SuppressLint("Recycle") Cursor cursor = database.rawQuery(query, new String[] {}); + if (cursor.getCount() > 0) { + Log.d("WebSocket", String.valueOf(cursor.getCount())); + for (int i = 1; i < cursor.getCount(); i++) { + Log.d("WebSocket", String.valueOf(i)); + try { + String relayUrl = cursor.getString(i); + Relay relay = new Relay(relayUrl, this); + relayList.add(relay); + } catch (IOException e) { + Log.d("WebSocket", e.toString()); + } + } + } + return relayList; + } } diff --git a/android/app/src/main/java/com/nostros/modules/RelayPoolModule.java b/android/app/src/main/java/com/nostros/modules/RelayPoolModule.java new file mode 100644 index 0000000..936b0e1 --- /dev/null +++ b/android/app/src/main/java/com/nostros/modules/RelayPoolModule.java @@ -0,0 +1,82 @@ +package com.nostros.modules; + +import android.util.Log; + +import com.facebook.react.bridge.Callback; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.nostros.classes.Relay; + +import java.io.IOException; +import java.util.List; + +public class RelayPoolModule extends ReactContextBaseJavaModule { + protected List relays; + private String userPubKey; + private DatabaseModule database; + + public RelayPoolModule(ReactApplicationContext reactContext) { + database = new DatabaseModule(reactContext.getFilesDir().getAbsolutePath()); + + List relayList = database.getRelays(); + if (relayList.isEmpty()) { + try { + relayList.add(new Relay("wss://relay.damus.io", database)); + } catch (IOException e) { + Log.d("WebSocket", e.toString()); + } + } + relays = relayList; + } + + @Override + public String getName() { + return "RelayPoolModule"; + } + + @ReactMethod + public void add(String url, Callback callback) { + try { + Relay relay = new Relay(url, database); + relay.connect(userPubKey); + relays.add(relay); + database.saveRelay(relay); + } catch (IOException e) { + Log.d("WebSocket", e.toString()); + } + callback.invoke(); + } + + @ReactMethod + public void remove(String url, Callback callback) { + for (Relay relay : relays) { + if (relay.url.equals(url)) { + relay.disconnect(); + relays.remove(relay); + database.destroyRelay(relay); + } + } + callback.invoke(); + } + + @ReactMethod + public void connect(String pubKey, Callback callback) { + userPubKey = pubKey; + for (Relay relay : relays) { + try { + relay.connect(pubKey); + } catch (IOException e) { + Log.d("WebSocket", e.toString()); + } + } + callback.invoke(); + } + + @ReactMethod + public void send(String message) { + for (Relay relay : relays) { + relay.send(message); + } + } +} diff --git a/frontend/Components/ConfigPage/index.tsx b/frontend/Components/ConfigPage/index.tsx index f913c42..a4fb090 100644 --- a/frontend/Components/ConfigPage/index.tsx +++ b/frontend/Components/ConfigPage/index.tsx @@ -1,12 +1,4 @@ -import { - Button, - Divider, - Input, - Layout, - TopNavigation, - TopNavigationAction, - useTheme, -} from '@ui-kitten/components' +import { Button, Divider, Input, Layout, TopNavigation, useTheme } from '@ui-kitten/components' import React, { useContext, useEffect } from 'react' import { Clipboard, StyleSheet } from 'react-native' import { AppContext } from '../../Contexts/AppContext' @@ -49,9 +41,10 @@ export const ConfigPage: React.FC = () => { } const renderBackAction = (): JSX.Element => ( - } +