handle "Invalid JSON RPC response" error by restarting RPC server

This commit is contained in:
Roman Volosovskyi 2016-12-11 08:35:36 +02:00
parent f74944ac2d
commit 6c1f24b211
15 changed files with 239 additions and 42 deletions

View File

@ -14,5 +14,5 @@ android {
dependencies { dependencies {
compile 'com.facebook.react:react-native:+' compile 'com.facebook.react:react-native:+'
compile(group: 'status-im', name: 'status-go', version: 'jail-isconnected', ext: 'aar') compile(group: 'status-im', name: 'status-go', version: 'restart-rpc', ext: 'aar')
} }

View File

@ -32,6 +32,18 @@ public class StatusConnector extends ServiceConnector {
} }
} }
public void startRPC() {
if (checkBound()) {
sendMessage(null, StatusMessages.MSG_START_RPC, null);
}
}
public void stopRPC() {
if (checkBound()) {
sendMessage(null, StatusMessages.MSG_STOP_RPC, null);
}
}
public void login(String callbackIdentifier, String address, String password) { public void login(String callbackIdentifier, String address, String password) {
if (checkBound()) { if (checkBound()) {

View File

@ -59,4 +59,14 @@ public class StatusMessages {
*/ */
public static final int MSG_DISCARD_TRANSACTION = 11; public static final int MSG_DISCARD_TRANSACTION = 11;
/**
* Start RPC server
*/
static final int MSG_START_RPC = 12;
/**
* Stop RPC server
*/
static final int MSG_STOP_RPC = 13;
} }

View File

@ -144,6 +144,28 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL
status.startNode(callbackIdentifier); status.startNode(callbackIdentifier);
} }
@ReactMethod
public void startNodeRPCServer() {
Log.d(TAG, "startNodeRPCServer");
final Activity activity = getCurrentActivity();
if (activity == null) {
return;
}
status.startRPC();
}
@ReactMethod
public void stopNodeRPCServer() {
Log.d(TAG, "stopNodeRPCServer");
final Activity activity = getCurrentActivity();
if (activity == null) {
return;
}
status.stopRPC();
}
@ReactMethod @ReactMethod
public void login(String address, String password, Callback callback) { public void login(String address, String password, Callback callback) {
Log.d(TAG, "login"); Log.d(TAG, "login");

View File

@ -143,6 +143,14 @@ public class StatusService extends Service {
callJail(message); callJail(message);
break; break;
case StatusMessages.MSG_START_RPC:
startRPC();
break;
case StatusMessages.MSG_STOP_RPC:
stopRPC();
break;
default: default:
return false; return false;
} }
@ -188,6 +196,14 @@ public class StatusService extends Service {
createAndSendReply(message, StatusMessages.MSG_STOP_NODE, null); createAndSendReply(message, StatusMessages.MSG_STOP_NODE, null);
} }
private void startRPC() {
Statusgo.StartNodeRPCServer();
}
private void stopRPC() {
Statusgo.StopNodeRPCServer();
}
private void createAccount(Message message) { private void createAccount(Message message) {
Bundle data = message.getData(); Bundle data = message.getData();

View File

@ -59,6 +59,68 @@ RCT_EXPORT_METHOD(callJail:(NSString *)chatId
}); });
} }
const int STATE_ACTIVE = 0;
const int STATE_LOCKED_WITH_ACTIVE_APP = 1;
const int STATE_BACKGROUND = 2;
const int STATE_LOCKED_WITH_INACTIVE_APP = 3;
int wozniakConstant = STATE_ACTIVE;
static void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
// the "com.apple.springboard.lockcomplete" notification will always come after the "com.apple.springboard.lockstate" notification
CFStringRef nameCFString = (CFStringRef)name;
NSString *lockState = (__bridge NSString*)nameCFString;
NSLog(@"Darwin notification NAME = %@",name);
NSString* sm = [NSString stringWithFormat:@"%i", wozniakConstant];
NSString *s1 = [NSString stringWithFormat:@"%@ %@", @"LOCK MAGIC", sm];
NSLog(s1);
if([lockState isEqualToString:@"com.apple.springboard.lockcomplete"])
{
NSLog(@"DEVICE LOCKED");
// User locks phone when application is active
if(wozniakConstant == STATE_ACTIVE){
wozniakConstant = STATE_LOCKED_WITH_ACTIVE_APP;
StopNodeRPCServer();
}
// Here lockcomplete event comes when app is unlocked
// because it couldn't come when locking happened
// as application was not active (it could not handle callback)
if (wozniakConstant == STATE_LOCKED_WITH_INACTIVE_APP) {
wozniakConstant = STATE_ACTIVE;
StopNodeRPCServer();
StartNodeRPCServer();
}
}
else
{
NSLog(@"LOCK STATUS CHANGED");
NSString *s = [NSString stringWithFormat:@"%@ %@", @"LOCK", lockState];
NSLog(s);
// if lockstate happens before lockcomplete it means
// that phone was locked when application was not active
if(wozniakConstant == STATE_ACTIVE){
wozniakConstant = STATE_LOCKED_WITH_INACTIVE_APP;
}
if(wozniakConstant == STATE_BACKGROUND){
wozniakConstant = STATE_ACTIVE;
StartNodeRPCServer();
}
// one more lockstate event comes along with lockcomplete
// when phone is locked with active application
if(wozniakConstant == STATE_LOCKED_WITH_ACTIVE_APP){
wozniakConstant = STATE_BACKGROUND;
}
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
#pragma mark - startNode #pragma mark - startNode
//////////////////////////////////////////////////////////////////// startNode //////////////////////////////////////////////////////////////////// startNode
@ -83,23 +145,57 @@ RCT_EXPORT_METHOD(startNode:(RCTResponseSenderBlock)onResultCallback) {
}else }else
NSLog(@"folderName: %@", folderName); NSLog(@"folderName: %@", folderName);
NSString *peer1 = @"enode://5f23bf4913dd005ce945648cb12d3ef970069818d8563a3fe054e5e1dc3898b9cb83e0af1f51b2dce75eaffc76e93f996caf538e21c5b64db5fa324958d59630@95.85.40.211:30303";
NSString *peer2 = @"enode://b9de2532421f15ac55da9d9a7cddc0dc08b0d646d631fd7ab2a170bd2163fb86b095dd8bde66b857592812f7cd9539f2919b6c64bc1a784a1d1c6ec8137681ed@188.166.229.119:30303";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^(void) { ^(void) {
StartNode((char *) [folderName.path UTF8String]); StartNode((char *) [folderName.path UTF8String]);
}); });
NSString *peer1 = @"enode://5f23bf4913dd005ce945648cb12d3ef970069818d8563a3fe054e5e1dc3898b9cb83e0af1f51b2dce75eaffc76e93f996caf538e21c5b64db5fa324958d59630@95.85.40.211:30303";
NSString *peer2 = @"enode://b9de2532421f15ac55da9d9a7cddc0dc08b0d646d631fd7ab2a170bd2163fb86b095dd8bde66b857592812f7cd9539f2919b6c64bc1a784a1d1c6ec8137681ed@188.166.229.119:30303";
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)),
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^(void) { ^(void) {
AddPeer((char *) [peer1 UTF8String]); AddPeer((char *) [peer1 UTF8String]);
AddPeer((char *) [peer2 UTF8String]); AddPeer((char *) [peer2 UTF8String]);
}); });
onResultCallback(@[[NSNull null]]); onResultCallback(@[[NSNull null]]);
//Screen lock notifications
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
NULL, // observer
displayStatusChanged, // callback
CFSTR("com.apple.springboard.lockcomplete"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
NULL, // observer
displayStatusChanged, // callback
CFSTR("com.apple.springboard.lockstate"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
return; return;
} }
} }
////////////////////////////////////////////////////////////////////
#pragma mark - StartNodeRPCServer method
//////////////////////////////////////////////////////////////////// createAccount
RCT_EXPORT_METHOD(startNodeRPCServer) {
#if DEBUG
NSLog(@"StartNodeRPCServer() method called");
#endif
StartNodeRPCServer();
}
////////////////////////////////////////////////////////////////////
#pragma mark - StopNodeRPCServer method
//////////////////////////////////////////////////////////////////// createAccount
RCT_EXPORT_METHOD(stopNodeRPCServer) {
#if DEBUG
NSLog(@"StopNodeRPCServer() method called");
#endif
StopNodeRPCServer();
}
RCT_EXPORT_METHOD(stopNode:(RCTResponseSenderBlock)callback) { RCT_EXPORT_METHOD(stopNode:(RCTResponseSenderBlock)callback) {
#if DEBUG #if DEBUG
NSLog(@"stopNode() method called"); NSLog(@"stopNode() method called");

View File

@ -25,7 +25,7 @@
<artifactItem> <artifactItem>
<groupId>status-im</groupId> <groupId>status-im</groupId>
<artifactId>status-go-ios-simulator</artifactId> <artifactId>status-go-ios-simulator</artifactId>
<version>jail-isconnected</version> <version>restart-rpc2</version>
<type>zip</type> <type>zip</type>
<overWrite>true</overWrite> <overWrite>true</overWrite>
<outputDirectory>./</outputDirectory> <outputDirectory>./</outputDirectory>

View File

@ -122,4 +122,4 @@
;; Clipboard ;; Clipboard
(defn copy-to-clipboard [text] (defn copy-to-clipboard [text]
(.setString (.-Clipboard react-native) text)) (.setString (.-Clipboard react-native) text))

View File

@ -62,6 +62,29 @@
(when status (when status
(call-module #(.startNode status on-result)))) (call-module #(.startNode status on-result))))
(defn stop-rpc-server []
(when status
(call-module #(.stopNodeRPCServer status))))
(defn start-rpc-server []
(when status
(call-module #(.startNodeRPCServer status))))
(defonce restarting-rpc (atom false))
(defn restart-rpc []
(when-not @restarting-rpc
(reset! restarting-rpc true)
(log/debug :restrt-rpc-on-post-error)
;; todo maybe it would be better to use something like
;; restart-rpc-server on status-go side
(stop-rpc-server)
(start-rpc-server)
(go (<! (timeout 3000))
(reset! restarting-rpc false))))
(defonce account-creation? (atom false)) (defonce account-creation? (atom false))
(defn create-account [password on-result] (defn create-account [password on-result]

View File

@ -24,7 +24,8 @@
status-im.network.handlers status-im.network.handlers
[status-im.utils.types :as t] [status-im.utils.types :as t]
[status-im.constants :refer [console-chat-id]] [status-im.constants :refer [console-chat-id]]
[status-im.utils.ethereum-network :as enet])) [status-im.utils.ethereum-network :as enet]
[status-im.protocol.core :as protocol]))
;; -- Common -------------------------------------------------------------- ;; -- Common --------------------------------------------------------------

View File

@ -67,7 +67,7 @@
(.addListener keyboard (.addListener keyboard
"keyboardWillHide" "keyboardWillHide"
#(when-not (= 0 @keyboard-height) #(when-not (= 0 @keyboard-height)
(dispatch [:set :keyboard-height 0]))) (dispatch [:set :keyboard-height 0])))
(.hide splash-screen)) (.hide splash-screen))
:render :render
(fn [] (fn []

View File

@ -60,6 +60,7 @@
::d/delivery-options)) ::d/delivery-options))
(def stop-watching-all! f/remove-all-filters!) (def stop-watching-all! f/remove-all-filters!)
(def reset-all-pending-messages! d/reset-all-pending-messages!)
(defn init-whisper! (defn init-whisper!
[{:keys [rpc-url identity groups callback [{:keys [rpc-url identity groups callback

View File

@ -12,38 +12,42 @@
[status-im.i18n :refer [label]] [status-im.i18n :refer [label]]
[status-im.utils.random :as random] [status-im.utils.random :as random]
[taoensso.timbre :as log :refer-macros [debug]] [taoensso.timbre :as log :refer-macros [debug]]
[status-im.constants :as c])) [status-im.constants :as c]
[status-im.components.status :as status]))
(register-handler :initialize-protocol (register-handler :initialize-protocol
(fn [db [_ current-account-id]] (fn [db [_ current-account-id]]
(let [{:keys [public-key status updates-public-key (let [{:keys [public-key status updates-public-key
updates-private-key]} updates-private-key]}
(get-in db [:accounts current-account-id])] (get-in db [:accounts current-account-id])]
(let [groups (chats/get-active-group-chats) (if public-key
w3 (protocol/init-whisper! (let [groups (chats/get-active-group-chats)
{:rpc-url c/ethereum-rpc-url w3 (protocol/init-whisper!
:identity public-key {:rpc-url c/ethereum-rpc-url
:groups groups :identity public-key
:callback #(dispatch [:incoming-message %1 %2]) :groups groups
:ack-not-received-s-interval 125 :callback #(dispatch [:incoming-message %1 %2])
:default-ttl 120 :ack-not-received-s-interval 125
:send-online-s-interval 180 :default-ttl 120
:ttl {} :send-online-s-interval 180
:max-attempts-number 3 :ttl {}
:delivery-loop-ms-interval 500 :max-attempts-number 3
:profile-keypair {:public updates-public-key :delivery-loop-ms-interval 500
:private updates-private-key} :profile-keypair {:public updates-public-key
:hashtags (u/get-hashtags status) :private updates-private-key}
:pending-messages (pending-messages/get-all) :hashtags (u/get-hashtags status)
:contacts (keep (fn [{:keys [whisper-identity :pending-messages (pending-messages/get-all)
public-key :contacts (keep (fn [{:keys [whisper-identity
private-key]}] public-key
(when (and public-key private-key) private-key]}]
{:identity whisper-identity (when (and public-key private-key)
:keypair {:public public-key {:identity whisper-identity
:private private-key}})) :keypair {:public public-key
(contacts/get-all))})] :private private-key}}))
(assoc db :web3 w3))))) (contacts/get-all))
:post-error-callback #(dispatch [::post-error %])})]
(assoc db :web3 w3))
db))))
(register-handler :update-sync-state (register-handler :update-sync-state
(u/side-effect! (u/side-effect!
@ -175,7 +179,7 @@
(register-handler ::you-removed-from-group (register-handler ::you-removed-from-group
(u/side-effect! (u/side-effect!
(fn [{:keys [web3]} (fn [{:keys [web3]}
[_ {:keys [from] [_ {:keys [from]
{:keys [group-id timestamp] :as payload} :payload}]] {:keys [group-id timestamp] :as payload} :payload}]]
(when (chats/new-update? timestamp group-id) (when (chats/new-update? timestamp group-id)
(let [message (let [message
@ -191,7 +195,7 @@
(register-handler :participant-left-group (register-handler :participant-left-group
(u/side-effect! (u/side-effect!
(fn [{:keys [current-public-key]} (fn [{:keys [current-public-key]}
[_ {:keys [from] [_ {:keys [from]
{:keys [group-id timestamp] :as payload} :payload}]] {:keys [group-id timestamp] :as payload} :payload}]]
(when (and (not= current-public-key from) (when (and (not= current-public-key from)
(chats/is-active? group-id) (chats/is-active? group-id)
@ -344,3 +348,10 @@
(dispatch [:update-contact! contact]) (dispatch [:update-contact! contact])
(dispatch [:watch-contact contact])) (dispatch [:watch-contact contact]))
(dispatch [:add-chat from chat]))))))) (dispatch [:add-chat from chat])))))))
(register-handler ::post-error
(u/side-effect!
(fn [_ [_ error]]
(.log js/console error)
(when (re-find (re-pattern "Could not connect to the server.") (.-message error))
(status/restart-rpc)))))

View File

@ -127,9 +127,12 @@
:last-attempt (u/timestamp))))) :last-attempt (u/timestamp)))))
(defn delivery-callback (defn delivery-callback
[web3 {:keys [id requires-ack? to]}] [web3 post-error-callback {:keys [id requires-ack? to]}]
(fn [error _] (fn [error _]
(when error (log/warn :shh-post-error error)) (when error
(log/warn :shh-post-error error)
(when post-error-callback
(post-error-callback error)))
(when-not error (when-not error
(debug :delivery-callback) (debug :delivery-callback)
(message-was-sent! web3 id to) (message-was-sent! web3 id to)
@ -143,10 +146,12 @@
(s/def ::default-ttl ::pos-int) (s/def ::default-ttl ::pos-int)
(s/def ::send-online-s-interval ::pos-int) (s/def ::send-online-s-interval ::pos-int)
(s/def ::online-message fn?) (s/def ::online-message fn?)
(s/def ::post-error-callback fn?)
(s/def ::delivery-options (s/def ::delivery-options
(s/keys :req-un [::delivery-loop-ms-interval ::ack-not-received-s-interval (s/keys :req-un [::delivery-loop-ms-interval ::ack-not-received-s-interval
::max-attempts-number ::default-ttl ::send-online-s-interval] ::max-attempts-number ::default-ttl ::send-online-s-interval
::post-error-callback]
:opt-un [::online-message])) :opt-un [::online-message]))
(defn should-be-retransmitted? (defn should-be-retransmitted?
@ -180,7 +185,7 @@
(defn run-delivery-loop! (defn run-delivery-loop!
[web3 {:keys [delivery-loop-ms-interval default-ttl ttl-config [web3 {:keys [delivery-loop-ms-interval default-ttl ttl-config
send-online-s-interval online-message] send-online-s-interval online-message post-error-callback]
:as options}] :as options}]
{:pre [(valid? ::delivery-options options)]} {:pre [(valid? ::delivery-options options)]}
(debug :run-delivery-loop!) (debug :run-delivery-loop!)
@ -201,7 +206,7 @@
(when (should-be-retransmitted? options data) (when (should-be-retransmitted? options data)
(try (try
(let [message' (check-ttl message type ttl-config default-ttl) (let [message' (check-ttl message type ttl-config default-ttl)
callback (delivery-callback web3 data)] callback (delivery-callback web3 post-error-callback data)]
(t/post-message! web3 message' callback)) (t/post-message! web3 message' callback))
(catch :default err (catch :default err
(log/error :post-message-error err)) (log/error :post-message-error err))

View File

@ -25,7 +25,7 @@
(defn handle-qr-request (defn handle-qr-request
[db [_ context data]] [db [_ context data]]
(let [handler (get-in db [:qr-codes context])] (when-let [handler (get-in db [:qr-codes context])]
(dispatch [handler context data]))) (dispatch [handler context data])))
(defn clear-qr-request [db [_ context]] (defn clear-qr-request [db [_ context]]