Fetch notifications

This commit is contained in:
koalasat
2024-07-09 21:38:25 +02:00
parent 0e6ae63ac4
commit 7388b4f6de
14 changed files with 204 additions and 22 deletions

View File

@ -0,0 +1,25 @@
import os
import site
import sys
# First, drop system-sites related paths.
original_sys_path = sys.path[:]
known_paths = set()
for path in {"/usr/local/lib/python3.12/site-packages"}:
site.addsitedir(path, known_paths=known_paths)
system_paths = set(
os.path.normcase(path) for path in sys.path[len(original_sys_path) :]
)
original_sys_path = [
path for path in original_sys_path if os.path.normcase(path) not in system_paths
]
sys.path = original_sys_path
# Second, add lib directories.
# ensuring .pth file are processed.
for path in [
"/tmp/pip-build-env-wwuhobll/overlay/lib/python3.12/site-packages",
"/tmp/pip-build-env-wwuhobll/normal/lib/python3.12/site-packages",
]:
assert path not in sys.path
site.addsitedir(path)

View File

@ -0,0 +1 @@
git+https://github.com/Reckless-Satoshi/drf-openapi-tester.git@soften-django-requirements (from -r requirements_dev.txt (line 3))

Submodule api/lightning/pip-req-build-bfeegnca added at 2af4d20743

View File

@ -7,6 +7,7 @@ import EncryptedStorage from 'react-native-encrypted-storage';
import { name as app_name, version as app_version } from './package.json'; import { name as app_name, version as app_version } from './package.json';
import TorModule from './native/TorModule'; import TorModule from './native/TorModule';
import RoboIdentitiesModule from './native/RoboIdentitiesModule'; import RoboIdentitiesModule from './native/RoboIdentitiesModule';
import NotificationsModule from './native/NotificationsModule';
const backgroundColors = { const backgroundColors = {
light: 'white', light: 'white',
@ -62,6 +63,7 @@ const App = () => {
webViewRef.current?.injectJavaScript( webViewRef.current?.injectJavaScript(
`(function() {window.NativeRobosats?.loadCookie(${json});})();`, `(function() {window.NativeRobosats?.loadCookie(${json});})();`,
); );
return value;
} }
}); });
}; };
@ -72,7 +74,10 @@ const App = () => {
loadCookie('settings_light_qr'); loadCookie('settings_light_qr');
loadCookie('settings_network'); loadCookie('settings_network');
loadCookie('settings_use_proxy'); loadCookie('settings_use_proxy');
loadCookie('garage_slots').then(() => injectMessageResolve(responseId)); loadCookie('garage_slots').then((slots) => {
NotificationsModule.monitorOrders(slots ?? '{}');
injectMessageResolve(responseId);
});
}; };
const onCatch = (dataId: string, event: any) => { const onCatch = (dataId: string, event: any) => {

View File

@ -13,6 +13,7 @@ import androidx.work.WorkManager;
import com.facebook.react.ReactActivity; import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate; import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView; import com.facebook.react.ReactRootView;
import com.robosats.workers.NotificationWorker; import com.robosats.workers.NotificationWorker;
@ -75,7 +76,7 @@ public class MainActivity extends ReactActivity {
// ExistingPeriodicWorkPolicy.KEEP, periodicWorkRequest); // ExistingPeriodicWorkPolicy.KEEP, periodicWorkRequest);
OneTimeWorkRequest workRequest = OneTimeWorkRequest workRequest =
new OneTimeWorkRequest.Builder(NotificationWorker.class) new OneTimeWorkRequest.Builder(NotificationWorker.class)
.setInitialDelay(5, TimeUnit.SECONDS) .setInitialDelay(25, TimeUnit.SECONDS)
.build(); .build();
WorkManager.getInstance(getApplicationContext()) WorkManager.getInstance(getApplicationContext())

View File

@ -4,6 +4,7 @@ import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager; import com.facebook.react.uimanager.ViewManager;
import com.robosats.modules.NotificationsModule;
import com.robosats.modules.RoboIdentitiesModule; import com.robosats.modules.RoboIdentitiesModule;
import com.robosats.modules.TorModule; import com.robosats.modules.TorModule;
@ -23,6 +24,7 @@ public class RobosatsPackage implements ReactPackage {
List<NativeModule> modules = new ArrayList<>(); List<NativeModule> modules = new ArrayList<>();
modules.add(new TorModule(reactContext)); modules.add(new TorModule(reactContext));
modules.add(new NotificationsModule(reactContext));
modules.add(new RoboIdentitiesModule(reactContext)); modules.add(new RoboIdentitiesModule(reactContext));
return modules; return modules;

View File

@ -0,0 +1,30 @@
package com.robosats.modules;
import android.content.SharedPreferences;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class NotificationsModule extends ReactContextBaseJavaModule {
public NotificationsModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "NotificationsModule";
}
@ReactMethod
public void monitorOrders(String slots_json) {
String PREFS_NAME = "Notifications";
String KEY_DATA = "Slots";
SharedPreferences sharedPreferences = getReactApplicationContext().getSharedPreferences(PREFS_NAME, ReactApplicationContext.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(KEY_DATA, slots_json);
editor.apply();
}
}

View File

@ -1,5 +1,6 @@
package com.robosats.modules; package com.robosats.modules;
import android.app.Application;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -11,6 +12,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule; import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.robosats.tor.TorKmp;
import com.robosats.tor.TorKmpManager; import com.robosats.tor.TorKmpManager;
import org.json.JSONException; import org.json.JSONException;
@ -30,10 +32,11 @@ import okhttp3.Response;
public class TorModule extends ReactContextBaseJavaModule { public class TorModule extends ReactContextBaseJavaModule {
private TorKmpManager torKmpManager;
private ReactApplicationContext context; private ReactApplicationContext context;
public TorModule(ReactApplicationContext reactContext) { public TorModule(ReactApplicationContext reactContext) {
context = reactContext; context = reactContext;
TorKmp torKmpManager = new TorKmp((Application) context.getApplicationContext());
TorKmpManager.INSTANCE.updateTorKmpObject(torKmpManager);
} }
@Override @Override
@ -46,7 +49,8 @@ public class TorModule extends ReactContextBaseJavaModule {
OkHttpClient client = new OkHttpClient.Builder() OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS) // Set connection timeout .connectTimeout(60, TimeUnit.SECONDS) // Set connection timeout
.readTimeout(30, TimeUnit.SECONDS) // Set read timeout .readTimeout(30, TimeUnit.SECONDS) // Set read timeout
.proxy(torKmpManager.getProxy()).build(); .proxy(TorKmpManager.INSTANCE.getTorKmpObject().getProxy())
.build();
Request.Builder requestBuilder = new Request.Builder().url(url); Request.Builder requestBuilder = new Request.Builder().url(url);
@ -90,7 +94,7 @@ public class TorModule extends ReactContextBaseJavaModule {
@ReactMethod @ReactMethod
public void getTorStatus() { public void getTorStatus() {
String torState = torKmpManager.getTorState().getState().name(); String torState = TorKmpManager.INSTANCE.getTorKmpObject().getTorState().getState().name();
WritableMap payload = Arguments.createMap(); WritableMap payload = Arguments.createMap();
payload.putString("torStatus", torState); payload.putString("torStatus", torState);
context context
@ -100,7 +104,7 @@ public class TorModule extends ReactContextBaseJavaModule {
@ReactMethod @ReactMethod
public void isConnected() { public void isConnected() {
String isConnected = String.valueOf(torKmpManager.isConnected()); String isConnected = String.valueOf(TorKmpManager.INSTANCE.getTorKmpObject().isConnected());
WritableMap payload = Arguments.createMap(); WritableMap payload = Arguments.createMap();
payload.putString("isConnected", isConnected); payload.putString("isConnected", isConnected);
context context
@ -110,7 +114,7 @@ public class TorModule extends ReactContextBaseJavaModule {
@ReactMethod @ReactMethod
public void isStarting() { public void isStarting() {
String isStarting = String.valueOf(torKmpManager.isStarting()); String isStarting = String.valueOf(TorKmpManager.INSTANCE.getTorKmpObject().isStarting());
WritableMap payload = Arguments.createMap(); WritableMap payload = Arguments.createMap();
payload.putString("isStarting", isStarting); payload.putString("isStarting", isStarting);
context context
@ -120,7 +124,7 @@ public class TorModule extends ReactContextBaseJavaModule {
@ReactMethod @ReactMethod
public void stop() { public void stop() {
torKmpManager.getTorOperationManager().stopQuietly(); TorKmpManager.INSTANCE.getTorKmpObject().getTorOperationManager().stopQuietly();
WritableMap payload = Arguments.createMap(); WritableMap payload = Arguments.createMap();
context context
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
@ -129,8 +133,9 @@ public class TorModule extends ReactContextBaseJavaModule {
@ReactMethod @ReactMethod
public void start() { public void start() {
torKmpManager = new TorKmpManager(context.getCurrentActivity().getApplication()); TorKmp torKmp = new TorKmp(context.getCurrentActivity().getApplication());
torKmpManager.getTorOperationManager().startQuietly(); TorKmpManager.INSTANCE.updateTorKmpObject(torKmp);
TorKmpManager.INSTANCE.getTorKmpObject().getTorOperationManager().startQuietly();
WritableMap payload = Arguments.createMap(); WritableMap payload = Arguments.createMap();
context context
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
@ -139,8 +144,9 @@ public class TorModule extends ReactContextBaseJavaModule {
@ReactMethod @ReactMethod
public void restart() { public void restart() {
torKmpManager = new TorKmpManager(context.getCurrentActivity().getApplication()); TorKmp torKmp = new TorKmp(context.getCurrentActivity().getApplication());
torKmpManager.getTorOperationManager().restartQuietly(); TorKmpManager.INSTANCE.updateTorKmpObject(torKmp);
TorKmpManager.INSTANCE.getTorKmpObject().getTorOperationManager().restartQuietly();
WritableMap payload = Arguments.createMap(); WritableMap payload = Arguments.createMap();
context context
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
@ -149,7 +155,7 @@ public class TorModule extends ReactContextBaseJavaModule {
@ReactMethod @ReactMethod
public void newIdentity() { public void newIdentity() {
torKmpManager.newIdentity(context.getCurrentActivity().getApplication()); TorKmpManager.INSTANCE.getTorKmpObject().newIdentity(context.getCurrentActivity().getApplication());
WritableMap payload = Arguments.createMap(); WritableMap payload = Arguments.createMap();
context context
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)

View File

@ -28,7 +28,7 @@ import kotlinx.coroutines.*
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.net.Proxy import java.net.Proxy
class TorKmpManager(application : Application) { class TorKmp(application : Application) {
private val TAG = "TorListener" private val TAG = "TorListener"
@ -387,3 +387,15 @@ class TorKmpManager(application : Application) {
} }
} }
} }
object TorKmpManager {
private lateinit var torKmp: TorKmp
fun getTorKmpObject(): TorKmp {
return torKmp
}
fun updateTorKmpObject(newKmpObject: TorKmp) {
torKmp = newKmpObject
}
}

View File

@ -1,32 +1,123 @@
package com.robosats.workers; package com.robosats.workers;
import android.app.Application;
import android.app.NotificationChannel; import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.content.SharedPreferences;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import androidx.work.Worker; import androidx.work.Worker;
import androidx.work.WorkerParameters; import androidx.work.WorkerParameters;
import com.facebook.react.bridge.ReactApplicationContext;
import com.robosats.R; import com.robosats.R;
import com.robosats.tor.TorKmpManager;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class NotificationWorker extends Worker { public class NotificationWorker extends Worker {
private static final String CHANNEL_ID = "robosats_notifications"; private static final String CHANNEL_ID = "robosats_notifications";
private static final int NOTIFICATION_ID = 123; private static final String PREFS_NAME = "Notifications";
private static final String KEY_DATA = "Slots";
public NotificationWorker(Context context, WorkerParameters params) { public NotificationWorker(Context context, WorkerParameters params) {
super(context, params); super(context, params);
} }
@Override @Override
public Result doWork() { public Result doWork() {
displayNotification("Order #1111", "Test from the app");
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences(PREFS_NAME, ReactApplicationContext.MODE_PRIVATE);
String slotsJson = sharedPreferences.getString(KEY_DATA, null);
try {
assert slotsJson != null;
JSONObject slots = new JSONObject(slotsJson);
Iterator<String> it = slots.keys();
while (it.hasNext()) {
String robotToken = it.next();
JSONObject slot = (JSONObject) slots.get(robotToken);
JSONObject robots = slot.getJSONObject("robots");
String activeShortAlias = slot.getString("activeShortAlias");
JSONObject coordinatorRobot = robots.getJSONObject(activeShortAlias);
String coordinator = "satstralia";
fetchNotifications(coordinatorRobot, coordinator);
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
return Result.success(); return Result.success();
} }
private void displayNotification(String title, String message) { private void fetchNotifications(JSONObject robot, String coordinator) throws JSONException {
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS) // Set connection timeout
.readTimeout(30, TimeUnit.SECONDS) // Set read timeout
.proxy(TorKmpManager.INSTANCE.getTorKmpObject().getProxy())
.build();
Request.Builder requestBuilder = new Request.Builder().url("http://satstraoq35jffvkgpfoqld32nzw2siuvowanruindbfojowpwsjdgad.onion/api/notifications");
requestBuilder.addHeader("Authorization", "Token " + robot.getString("tokenSHA256"));
requestBuilder.get();
Request request = requestBuilder.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
Log.d("RobosatsError", e.toString());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String body = response.body() != null ? response.body().string() : "{}";
JSONObject headersJson = new JSONObject();
response.headers().names().forEach(name -> {
try {
headersJson.put(name, response.header(name));
} catch (JSONException e) {
throw new RuntimeException(e);
}
});
try {
JSONArray results = new JSONArray(body);
for (int i = 0; i < results.length(); i++) {
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences(PREFS_NAME, ReactApplicationContext.MODE_PRIVATE);
JSONObject notification = results.getJSONObject(i);
Integer order_id = notification.getInt("order_id");
displayNotification(order_id, notification.getString("title"), coordinator);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(coordinator + order_id, String.valueOf(notification.getInt("created_at")));
editor.apply();
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
});
}
private void displayNotification(Integer order_id, String message, String coordinator) {
NotificationManager notificationManager = (NotificationManager) NotificationManager notificationManager = (NotificationManager)
getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE); getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
@ -37,12 +128,12 @@ public class NotificationWorker extends Worker {
NotificationCompat.Builder builder = NotificationCompat.Builder builder =
new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID) new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID)
.setContentTitle(title) .setContentTitle("Order #" + order_id)
.setContentText(message) .setContentText(message)
.setSmallIcon(R.mipmap.ic_launcher_round) .setSmallIcon(R.mipmap.ic_launcher_round)
.setPriority(NotificationCompat.PRIORITY_DEFAULT); .setPriority(NotificationCompat.PRIORITY_DEFAULT);
notificationManager.notify(NOTIFICATION_ID, builder.build()); notificationManager.notify(order_id, builder.build());
} }
} }

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,8 @@
import { NativeModules } from 'react-native';
const { NotificationsModule } = NativeModules;
interface NotificationsModuleInterface {
monitorOrders: (slotsJson: string) => void;
}
export default NotificationsModule as NotificationsModuleInterface;

View File

@ -2,8 +2,8 @@ import { NativeModules } from 'react-native';
const { RoboIdentitiesModule } = NativeModules; const { RoboIdentitiesModule } = NativeModules;
interface RoboIdentitiesModuleInterface { interface RoboIdentitiesModuleInterface {
generateRoboname: (initialString: String) => Promise<string>; generateRoboname: (initialString: string) => Promise<string>;
generateRobohash: (initialString: String) => Promise<string>; generateRobohash: (initialString: string) => Promise<string>;
} }
export default RoboIdentitiesModule as RoboIdentitiesModuleInterface; export default RoboIdentitiesModule as RoboIdentitiesModuleInterface;