Flush host when network connectivity changes

pull/8441/head
Muxi Yan 8 years ago
parent a8d6681cce
commit e1443b195e
  1. 40
      src/objective-c/GRPCClient/GRPCCall.m
  2. 3
      src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
  3. 17
      src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
  4. 13
      src/objective-c/GRPCClient/private/GRPCHost.m
  5. 1
      src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h
  6. 2
      src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj

@ -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 */ = {

Loading…
Cancel
Save