Skip to content
Snippets Groups Projects
Commit e1443b19 authored by Muxi Yan's avatar Muxi Yan
Browse files

Flush host when network connectivity changes

parent a8d6681c
No related branches found
No related tags found
No related merge requests found
......@@ -375,20 +375,6 @@ static NSMutableDictionary *callFlags;
_state = GRXWriterStateStarted;
}
// Create a retain cycle so that this instance lives until the RPC finishes (or is cancelled).
// This makes RPCs in which the call isn't externally retained possible (as long as it is started
// before being autoreleased).
// Care is taken not to retain self strongly in any of the blocks used in this implementation, so
// that the life of the instance is determined by this retain cycle.
_retainSelf = self;
_responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable];
_wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path];
NSAssert(_wrappedCall, @"Error allocating RPC objects. Low memory?");
[self sendHeaders:_requestHeaders];
[self invokeCall];
// TODO(jcanizales): Extract this logic somewhere common.
NSString *host = [NSURL URLWithString:[@"https://" stringByAppendingString:_host]].host;
if (!host) {
......@@ -397,15 +383,35 @@ static NSMutableDictionary *callFlags;
}
__weak typeof(self) weakSelf = self;
_connectivityMonitor = [GRPCConnectivityMonitor monitorWithHost:host];
[_connectivityMonitor handleLossWithHandler:^{
void (^handler)() = ^{
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeUnavailable
userInfo:@{NSLocalizedDescriptionKey: @"Connectivity lost."}]];
[[GRPCHost hostWithAddress:strongSelf->_host] disconnect];
}
}];
};
[_connectivityMonitor handleLossWithHandler:handler
wifiStatusChangeHandler:handler];
// Create a retain cycle so that this instance lives until the RPC finishes
// (or is cancelled).
// This makes RPCs in which the call isn't externally retained possible (as
// long as it is started
// before being autoreleased).
// Care is taken not to retain self strongly in any of the blocks used in this
// implementation, so
// that the life of the instance is determined by this retain cycle.
_retainSelf = self;
_responseWriteable =
[[GRXConcurrentWriteable alloc] initWithWriteable:writeable];
_wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path];
NSAssert(_wrappedCall, @"Error allocating RPC objects. Low memory?");
[self sendHeaders:_requestHeaders];
[self invokeCall];
}
- (void)setState:(GRXWriterState)newState {
......
......@@ -73,5 +73,6 @@
* Only one handler is active at a time, so if this method is called again before the previous
* handler has been called, it might never be called at all (or yes, if it has already been queued).
*/
- (void)handleLossWithHandler:(nonnull void (^)())handler;
- (void)handleLossWithHandler:(void (^)())handler
wifiStatusChangeHandler:(void (^)())wifiStatusChangeHandler;
@end
......@@ -120,6 +120,7 @@ static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
@implementation GRPCConnectivityMonitor {
SCNetworkReachabilityRef _reachabilityRef;
GRPCReachabilityFlags *_previousReachabilityFlags;
}
- (nullable instancetype)initWithReachability:(nullable SCNetworkReachabilityRef)reachability {
......@@ -129,6 +130,13 @@ static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
if ((self = [super init])) {
_reachabilityRef = CFRetain(reachability);
_queue = dispatch_get_main_queue();
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) {
_previousReachabilityFlags =
[[GRPCReachabilityFlags alloc] initWithFlags:flags];
} else {
_previousReachabilityFlags = 0;
}
}
return self;
}
......@@ -149,11 +157,16 @@ static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
return returnValue;
}
- (void)handleLossWithHandler:(void (^)())handler {
- (void)handleLossWithHandler:(void (^)())handler
wifiStatusChangeHandler:(nonnull void (^)())wifiStatusChangeHandler {
[self startListeningWithHandler:^(GRPCReachabilityFlags *flags) {
if (!flags.isHostReachable) {
if (!flags.reachable && handler) {
handler();
} else if (flags.isWWAN ^ _previousReachabilityFlags.isWWAN &&
wifiStatusChangeHandler) {
wifiStatusChangeHandler();
}
_previousReachabilityFlags = flags;
}];
}
......
......@@ -43,6 +43,7 @@
#import "GRPCChannel.h"
#import "GRPCCompletionQueue.h"
#import "GRPCConnectivityMonitor.h"
#import "NSDictionary+GRPC.h"
NS_ASSUME_NONNULL_BEGIN
......@@ -52,6 +53,7 @@ NS_ASSUME_NONNULL_BEGIN
#define GRPC_OBJC_VERSION_STRING @"1.0.0"
static NSMutableDictionary *kHostCache;
static GRPCConnectivityMonitor *connectivityMonitor = nil;
@implementation GRPCHost {
// TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
......@@ -98,6 +100,16 @@ static NSMutableDictionary *kHostCache;
_address = address;
_secure = YES;
kHostCache[address] = self;
if (!connectivityMonitor) {
connectivityMonitor =
[GRPCConnectivityMonitor monitorWithHost:hostURL.host];
void (^handler)() = ^{
[GRPCHost flushChannelCache];
};
[connectivityMonitor handleLossWithHandler:handler
wifiStatusChangeHandler:handler];
}
}
}
return self;
......@@ -110,6 +122,7 @@ static NSMutableDictionary *kHostCache;
BOOL * _Nonnull stop) {
[host disconnect];
}];
connectivityMonitor = nil;
}
}
......
......@@ -65,3 +65,4 @@ GRPC_XMACRO_ITEM(interventionRequired, InterventionRequired)
GRPC_XMACRO_ITEM(connectionOnDemand, ConnectionOnDemand)
GRPC_XMACRO_ITEM(isLocalAddress, IsLocalAddress)
GRPC_XMACRO_ITEM(isDirect, IsDirect)
GRPC_XMACRO_ITEM(isWWAN, IsWWAN)
......@@ -156,7 +156,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
5347BF6C41E7888C1C05CD88 /* [CP] Copy Pods Resources */ = {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment