From 8e38393f04bcab5fa1774fa4a17870b13da321c3 Mon Sep 17 00:00:00 2001 From: Ulises M Date: Tue, 29 Oct 2024 21:13:57 -0600 Subject: [PATCH] feat: Add general infrastructure for status-backend integration --- shadow-cljs.edn | 10 +++- src/native_module/core.cljs | 88 ++++++++++++++++------------------ src/status_backend/config.cljs | 20 ++++++++ src/status_backend/core.cljs | 46 ++++++++++++++++++ src/status_im/config.cljs | 6 +++ src/utils/network/core.cljs | 16 +++++-- 6 files changed, 131 insertions(+), 55 deletions(-) create mode 100644 src/status_backend/config.cljs create mode 100644 src/status_backend/core.cljs diff --git a/shadow-cljs.edn b/shadow-cljs.edn index e4f8a4a01e..b184655987 100644 --- a/shadow-cljs.edn +++ b/shadow-cljs.edn @@ -82,7 +82,12 @@ status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN" status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN" status-im.config/ALCHEMY_OPTIMISM_GOERLI_TOKEN #shadow/env "ALCHEMY_OPTIMISM_GOERLI_TOKEN" - status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"} + status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN" + status-im.config/STATUS_BACKEND_ENABLED #shadow/env "STATUS_BACKEND_ENABLED" + ;; The dir /data musts exist before running the app. + status-im.config/STATUS_BACKEND_STORAGE_DIR #shadow/env "STATUS_BACKEND_STORAGE_DIR" + status-im.config/STATUS_BACKEND_PORT #shadow/env "STATUS_BACKEND_PORT" + status-im.config/STATUS_BACKEND_ADDRESS #shadow/env "STATUS_BACKEND_ADDRESS"} :compiler-options {:output-feature-set :es5 ;; We disable `:fn-deprecated` warnings because we ;; are managing deprecation via clj-kondo and we @@ -121,7 +126,8 @@ status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN" status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN" status-im.config/ALCHEMY_OPTIMISM_GOERLI_TOKEN #shadow/env "ALCHEMY_OPTIMISM_GOERLI_TOKEN" - status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"} + status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN" + status-im.config/STATUS_BACKEND_ENABLED false} :compiler-options {:output-feature-set :es6 ;;disable for android build as there ;;is an intermittent warning with deftype diff --git a/src/native_module/core.cljs b/src/native_module/core.cljs index eb5be90c6d..92615cc9d8 100644 --- a/src/native_module/core.cljs +++ b/src/native_module/core.cljs @@ -3,54 +3,30 @@ ["react-native" :as react-native] [clojure.string :as string] [native-module.utils :as native-utils] + [oops.core :as oops] [react-native.platform :as platform] + [status-backend.config :as status-backend.config] + [status-backend.core :as status-backend] + [status-im.config] [taoensso.timbre :as log] [utils.transforms :as types])) -(defn status - [] - (when (exists? (.-NativeModules react-native)) - (.-Status ^js (.-NativeModules react-native)))) +(defn- extract-from-native-modules [module] + (if status-im.config/STATUS_BACKEND_ENABLED + status-backend/fetch-js-obj + (some-> react-native + (oops/gobj-get "NativeModules") + (oops/gobj-get module)))) -(defn account-manager - [] - (when (exists? (.-NativeModules react-native)) - (.-AccountManager ^js (.-NativeModules react-native)))) - -(defn encryption - [] - (when (exists? (.-NativeModules react-native)) - (.-EncryptionUtils ^js (.-NativeModules react-native)))) - -(defn database - [] - (when (exists? (.-NativeModules react-native)) - (.-DatabaseManager ^js (.-NativeModules react-native)))) - -(defn ui-helper - [] - (when (exists? (.-NativeModules react-native)) - (.-UIHelper ^js (.-NativeModules react-native)))) - -(defn log-manager - [] - (when (exists? (.-NativeModules react-native)) - (.-LogManager ^js (.-NativeModules react-native)))) - -(defn utils - [] - (when (exists? (.-NativeModules react-native)) - (.-Utils ^js (.-NativeModules react-native)))) - -(defn network - [] - (when (exists? (.-NativeModules react-native)) - (.-NetworkManager ^js (.-NativeModules react-native)))) - -(defn mail-manager - [] - (when (exists? (.-NativeModules react-native)) - (.-MailManager ^js (.-NativeModules react-native)))) +(defn status [] (extract-from-native-modules "Status")) +(defn account-manager [] (extract-from-native-modules "AccountManager")) +(defn encryption [] (extract-from-native-modules "EncryptionUtils")) +(defn database [] (extract-from-native-modules "DatabaseManager")) +(defn ui-helper [] (extract-from-native-modules "UIHelper")) +(defn log-manager [] (extract-from-native-modules "LogManager")) +(defn utils [] (extract-from-native-modules "Utils")) +(defn network [] (extract-from-native-modules "NetworkManager")) +(defn mail-manager [] (extract-from-native-modules "MailManager")) (defn mail [opts callback] @@ -58,7 +34,9 @@ (defn init [handler] - (.addListener ^js (.-DeviceEventEmitter ^js react-native) "gethEvent" #(handler (.-jsonEvent ^js %)))) + (if status-im.config/STATUS_BACKEND_ENABLED + (status-backend/init-web-socket handler) + (.addListener ^js (.-DeviceEventEmitter ^js react-native) "gethEvent" #(handler (.-jsonEvent ^js %))))) (defn clear-web-data [] @@ -521,7 +499,9 @@ (defn backup-disabled-data-dir [] - (.backupDisabledDataDir ^js (utils))) + (if status-im.config/STATUS_BACKEND_ENABLED + status-backend.config/data-dir-path + (.backupDisabledDataDir ^js (utils)))) (defn fleets [] @@ -529,15 +509,27 @@ (defn keystore-dir [] - (.keystoreDir ^js (utils))) + (if status-im.config/STATUS_BACKEND_ENABLED + status-backend.config/keystore-dir-path + (.keystoreDir ^js (utils)))) (defn log-file-directory [] - (.logFileDirectory ^js (log-manager))) + (if status-im.config/STATUS_BACKEND_ENABLED + status-backend.config/log-dir-path + (.logFileDirectory ^js (log-manager)))) (defn init-status-go-logging [{:keys [enable? mobile-system? log-level log-request-go? callback]}] - (.initLogging ^js (log-manager) enable? mobile-system? log-level log-request-go? callback)) + (if status-im.config/STATUS_BACKEND_ENABLED + (.initLogging ^js (log-manager) + {:Enabled enable? + :MobileSystem mobile-system? + :Level log-level + :LogRequestGo log-request-go? + :LogRequestFile status-backend.config/log-request-file-path} + callback) + (.initLogging ^js (log-manager) enable? mobile-system? log-level log-request-go? callback))) (defn get-random-mnemonic [callback] diff --git a/src/status_backend/config.cljs b/src/status_backend/config.cljs new file mode 100644 index 0000000000..56f507fd40 --- /dev/null +++ b/src/status_backend/config.cljs @@ -0,0 +1,20 @@ +(ns status-backend.config + (:require [status-im.config])) + +(def ^:private url + (str "http://" + status-im.config/STATUS_BACKEND_ADDRESS + ":" + status-im.config/STATUS_BACKEND_PORT)) + +(def ^:private data-dir-path + (str status-im.config/STATUS_BACKEND_STORAGE_DIR "/data")) + +(def ^:private public-storage-dir + (str status-im.config/STATUS_BACKEND_STORAGE_DIR "/public")) + +(def status-go-url (str url "/statusgo/")) +(def signals-url (str url "/signals")) +(def keystore-dir-path (str data-dir-path "/keystore")) +(def log-dir-path (str data-dir-path "/log")) +(def log-request-file-path (str public-storage-dir "/requests.log")) \ No newline at end of file diff --git a/src/status_backend/core.cljs b/src/status_backend/core.cljs new file mode 100644 index 0000000000..231ae5f3e8 --- /dev/null +++ b/src/status_backend/core.cljs @@ -0,0 +1,46 @@ +(ns status-backend.core + (:require + [status-backend.config :as config] + [utils.network.core :as network] + [clojure.string :as string] + [oops.core :as oops] + [taoensso.timbre :as log])) + +(def ^:private default-fetch-params + {:method :POST + :headers {"Accept" "application/json" + "Content-Type" "application/json"}}) + +(defn fetch + ([endpoint] + (fetch endpoint nil (fn []))) + ([endpoint body-params] + (fetch endpoint body-params (fn []))) + ([endpoint body-params callback] + (let [url (str config/status-go-url endpoint) + params (assoc default-fetch-params :body body-params)] + (network/fetch url params callback)))) + +(defn- method-name->endpoint [s] + (let [first-letter-capitalized (string/capitalize (first s))] + (str first-letter-capitalized (subs s 1)))) + +(def fetch-js-obj + "Performs a request to the status-backend (by using `status-backend.core/fetch`) using + the method invoked as endpoint name. E.g + This call: (.myMethod fetch-js-obj params) + Is the same as: (fetch \"MyMethod\" params) + " + (js/Proxy. #js{} + #js{:get (fn [_target native-module-method-name] + (let [endpoint (method-name->endpoint native-module-method-name)] + (partial fetch endpoint)))})) + +(declare web-socket) + +(defn init-web-socket [on-message] + (defonce web-socket (js/WebSocket. config/signals-url)) + (oops/oset! web-socket "onopen" #(log/debug "[backend] Web Socket connected")) + (oops/oset! web-socket "onmessage" #(-> % (oops/oget "data") (on-message))) + (oops/oset! web-socket "onerror" #(log/error "[backend] Web Socket error" %)) + (oops/oset! web-socket "onclose" #(log/error "[backend] Web Socket closed" %))) diff --git a/src/status_im/config.cljs b/src/status_im/config.cljs index 98a632fc8c..ff360f85da 100644 --- a/src/status_im/config.cljs +++ b/src/status_im/config.cljs @@ -29,6 +29,12 @@ (goog-define WALLET_CONNECT_PROJECT_ID "87815d72a81d739d2a7ce15c2cfdefb3") (goog-define MIXPANEL_APP_ID "3350627") (goog-define MIXPANEL_TOKEN "5c73bda2d36a9f688a5ee45641fb6775") +(goog-define STATUS_BACKEND_ENABLED false) +;; Warn: /data musts exist before running the app if +;; `STATUS_BACKEND_ENABLED` is true. +(goog-define STATUS_BACKEND_STORAGE_DIR "") +(goog-define STATUS_BACKEND_PORT 9050) +(goog-define STATUS_BACKEND_ADDRESS "localhost") (def mainnet-rpc-url (str "https://eth-archival.rpc.grove.city/v1/" POKT_TOKEN)) (def goerli-rpc-url (str "https://goerli-archival.gateway.pokt.network/v1/lb/" POKT_TOKEN)) diff --git a/src/utils/network/core.cljs b/src/utils/network/core.cljs index f8cdaeb17f..726475d90d 100644 --- a/src/utils/network/core.cljs +++ b/src/utils/network/core.cljs @@ -1,6 +1,7 @@ (ns utils.network.core (:require - [clojure.string :as string])) + [clojure.string :as string] + [taoensso.timbre :as log])) (def url-regex #"https?://(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}(\.[a-z]{2,6})?\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)") @@ -41,7 +42,12 @@ (map :error) (not-any? identity))) -(defn chain-id-available? - [current-networks network] - (let [chain-id (get-in network [:config :NetworkId])] - (every? #(not= chain-id (get-in % [1 :config :NetworkId])) current-networks))) +(defn fetch [url {:keys [body] :as params} callback] + (let [js-params (cond-> params + (map? body) (update :body (comp js/JSON.stringify clj->js)) + :always clj->js)] + (-> (js/fetch url js-params) + (.then (fn [response] + (.text response))) + (.then callback) + (.catch #(log/error (str "Error while fetching: " url) %)))))