|
16 | 16 | #import "LKServerVersionRequestor.h" |
17 | 17 | #import "ECOChannelManager.h" |
18 | 18 |
|
19 | | -static NSIndexSet * PushFrameTypeList() { |
| 19 | +static NSIndexSet *PushFrameTypeList(void) { |
20 | 20 | static NSIndexSet *list; |
21 | 21 | static dispatch_once_t onceToken; |
22 | 22 | dispatch_once(&onceToken, ^{ |
|
27 | 27 | } |
28 | 28 |
|
29 | 29 | static NSString *const LKWhiteListDevicesKey = @"LKWhiteListDevicesKey"; |
| 30 | +static NSTimeInterval const LKWirelessAuthorizationTimeout = 30; |
| 31 | + |
| 32 | +static NSString *LKWirelessDeviceIdentifier(ECOChannelDeviceInfo *device) { |
| 33 | + if (!device.uuid.length || !device.appInfo.appId.length) { |
| 34 | + return nil; |
| 35 | + } |
| 36 | + return [NSString stringWithFormat:@"%@_%@", device.uuid, device.appInfo.appId]; |
| 37 | +} |
30 | 38 |
|
31 | 39 | @implementation Lookin_PTChannel (LKConnection) |
32 | 40 |
|
@@ -93,7 +101,7 @@ @interface LKConnectionManager () <Lookin_PTChannelDelegate> |
93 | 101 | @property(nonatomic, strong) NSMutableArray<ECOChannelDeviceInfo *> *connectWirelessDevices; |
94 | 102 | @property(nonatomic, strong) NSMutableArray<ECOChannelDeviceInfo *> *notConnectWirelessDevices; |
95 | 103 | @property(nonatomic, strong) ECOChannelManager *wirelessChannel; |
96 | | -@property(nonatomic, strong) NSMutableDictionary *authStateChangedBlocks; |
| 104 | +@property(nonatomic, strong) NSMutableDictionary<NSString *, ECOChannelAuthStateChangedBlock> *authStateChangedBlocks; |
97 | 105 |
|
98 | 106 | @property(nonatomic, strong) NSMutableArray<ECOChannelDeviceInfo *> *whitelistDevices; |
99 | 107 |
|
@@ -173,9 +181,12 @@ - (RACSignal *)tryToConnectAllPorts { |
173 | 181 | return [[RACSignal zip:@[[self _tryToConnectAllSimulatorPorts], |
174 | 182 | [self _tryToConnectAllUSBDevices], |
175 | 183 | [self _tryToConnectToAllWirelessDevice]]] map:^id _Nullable(RACTuple * _Nullable value) { |
176 | | - RACTupleUnpack(NSArray<Lookin_PTChannel *> *simulatorChannels, NSArray<Lookin_PTChannel *> *usbChannels, NSArray<ECOChannelDeviceInfo *> *wirelessDevices) = value; |
177 | | - NSArray *connectedChannels = [[simulatorChannels arrayByAddingObjectsFromArray:usbChannels] arrayByAddingObjectsFromArray:wirelessDevices]; |
178 | | - return connectedChannels; |
| 184 | + RACTupleUnpack(NSArray<Lookin_PTChannel *> *simulatorChannels, NSArray<Lookin_PTChannel *> *usbChannels, NSArray<ECOChannelDeviceInfo *> *wirelessDevices) = value; |
| 185 | + NSMutableArray<id<LookinChannelProtocol>> *connectedChannels = [NSMutableArray array]; |
| 186 | + [connectedChannels addObjectsFromArray:simulatorChannels]; |
| 187 | + [connectedChannels addObjectsFromArray:usbChannels]; |
| 188 | + [connectedChannels addObjectsFromArray:wirelessDevices]; |
| 189 | + return connectedChannels.copy; |
179 | 190 | }]; |
180 | 191 | } |
181 | 192 |
|
@@ -286,20 +297,25 @@ - (RACSignal *)_tryToConnectToAllWirelessDevice { |
286 | 297 |
|
287 | 298 | #pragma mark - Request |
288 | 299 |
|
289 | | -- (void)pushWithType:(unsigned int)pushType data:(NSObject *)data channel:(Lookin_PTChannel *)channel { |
| 300 | +- (void)pushWithType:(unsigned int)pushType data:(NSObject *)data channel:(id<LookinChannelProtocol>)channel { |
290 | 301 | if (!channel || !channel.isConnected) { |
291 | 302 | return; |
292 | 303 | } |
293 | 304 | NSError *archiveError = nil; |
294 | | - dispatch_data_t payload = [[NSKeyedArchiver archivedDataWithRootObject:data requiringSecureCoding:YES error:&archiveError] createReferencingDispatchData]; |
| 305 | + NSData *sendData = [NSKeyedArchiver archivedDataWithRootObject:data requiringSecureCoding:YES error:&archiveError]; |
295 | 306 | if (archiveError) { |
296 | 307 | NSAssert(NO, @""); |
297 | 308 | } |
298 | 309 | NSLog(@"LookinClient - pushData, type:%@", @(pushType)); |
299 | | - [channel sendFrameOfType:pushType tag:0 withPayload:payload callback:nil]; |
| 310 | + if ([channel isKindOfClass:ECOChannelDeviceInfo.class]) { |
| 311 | + [self.wirelessChannel sendPacket:sendData extraInfo:@{@"tag": @0, @"type": @(pushType)} toDevice:(ECOChannelDeviceInfo *)channel]; |
| 312 | + } else if ([channel isKindOfClass:Lookin_PTChannel.class]) { |
| 313 | + dispatch_data_t payload = [sendData createReferencingDispatchData]; |
| 314 | + [(Lookin_PTChannel *)channel sendFrameOfType:pushType tag:0 withPayload:payload callback:nil]; |
| 315 | + } |
300 | 316 | } |
301 | 317 |
|
302 | | -- (RACSignal *)requestWithType:(unsigned int)requestType data:(NSObject *)requestData channel:(Lookin_PTChannel *)channel { |
| 318 | +- (RACSignal *)requestWithType:(unsigned int)requestType data:(NSObject *)requestData channel:(id<LookinChannelProtocol>)channel { |
303 | 319 | return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { |
304 | 320 | // NSLog(@"LookinClient, level1 - will ping for request:%@, port:%@", @(type), @(channel.portNumber)); |
305 | 321 | NSTimeInterval timeoutInterval; |
@@ -457,7 +473,7 @@ - (void)_requestWithType:(unsigned int)requestType channel:(id<LookinChannelProt |
457 | 473 | } |
458 | 474 | } |
459 | 475 |
|
460 | | -- (void)cancelRequestWithType:(unsigned int)requestType channel:(Lookin_PTChannel *)channel { |
| 476 | +- (void)cancelRequestWithType:(unsigned int)requestType channel:(id<LookinChannelProtocol>)channel { |
461 | 477 | LKConnectionRequest *activeRequest = [channel.activeRequests lookin_firstFiltered:^BOOL(LKConnectionRequest *obj) { |
462 | 478 | return obj.type == requestType; |
463 | 479 | }]; |
@@ -506,91 +522,133 @@ - (void)_startListeningForWirelessDevices { |
506 | 522 | @weakify(self); |
507 | 523 | // 接收到数据回调 |
508 | 524 | self.wirelessChannel.receivedBlock = ^(ECOChannelDeviceInfo *device, NSData *data, NSDictionary *extraInfo) { |
509 | | - NSLog(@"🚀 Lookin receivedBlock device:%@", device); |
510 | | - NSNumber *tag = extraInfo[@"tag"]; |
511 | | - NSNumber *type = extraInfo[@"type"]; |
512 | | - LKConnectionRequest *activeRequest = [device.activeRequests lookin_firstFiltered:^BOOL(LKConnectionRequest *obj) { |
513 | | - return [@(obj.type) isEqualToNumber:type] && [@(obj.tag) isEqualToNumber:tag]; |
514 | | - }]; |
515 | | - if (!activeRequest) { |
516 | | - // 也许在 shouldAcceptFrameOfType 和 didReceiveFrame 两个时机之间,该 request 因为超时而被销毁了?有点玄学但确实偶尔会走到这里。 |
517 | | - return; |
518 | | - } |
519 | | - [self_weak_ _didReceiveDataWithChannel:device data:data activeRequest:activeRequest]; |
| 525 | + dispatch_async(dispatch_get_main_queue(), ^{ |
| 526 | + @strongify(self); |
| 527 | + NSNumber *tag = [extraInfo[@"tag"] isKindOfClass:NSNumber.class] ? extraInfo[@"tag"] : nil; |
| 528 | + NSNumber *type = [extraInfo[@"type"] isKindOfClass:NSNumber.class] ? extraInfo[@"type"] : nil; |
| 529 | + if (!tag || !type) { |
| 530 | + return; |
| 531 | + } |
| 532 | + LKConnectionRequest *activeRequest = [device.activeRequests lookin_firstFiltered:^BOOL(LKConnectionRequest *obj) { |
| 533 | + return [@(obj.type) isEqualToNumber:type] && [@(obj.tag) isEqualToNumber:tag]; |
| 534 | + }]; |
| 535 | + if (!activeRequest) { |
| 536 | + // 请求可能在数据到达前已超时。 |
| 537 | + return; |
| 538 | + } |
| 539 | + [self _didReceiveDataWithChannel:device data:data activeRequest:activeRequest]; |
| 540 | + }); |
520 | 541 | }; |
521 | 542 | // 设备连接变更 |
522 | 543 | self.wirelessChannel.deviceBlock = ^(ECOChannelDeviceInfo *device, BOOL isConnected) { |
523 | | - NSLog(@"🚀 Lookin deviceBlock device:%@", device); |
524 | | - if (isConnected && ![self_weak_.connectWirelessDevices containsObject:device]) { |
525 | | - if (!device.authorizedType && ![self_weak_ isWhiteListDevice:device]) { |
526 | | - if (![self_weak_.notConnectWirelessDevices containsObject:device]) { |
527 | | - [self_weak_.notConnectWirelessDevices addObject:device]; |
| 544 | + dispatch_async(dispatch_get_main_queue(), ^{ |
| 545 | + @strongify(self); |
| 546 | + if (isConnected && ![self.connectWirelessDevices containsObject:device]) { |
| 547 | + if (!device.authorizedType && ![self isWhiteListDevice:device]) { |
| 548 | + if (![self.notConnectWirelessDevices containsObject:device]) { |
| 549 | + [self.notConnectWirelessDevices addObject:device]; |
| 550 | + } |
| 551 | + } else { |
| 552 | + [[self _connectToWirelessDevice:device] subscribeNext:^(__unused ECOChannelDeviceInfo *connectedDevice) { |
| 553 | + } error:^(__unused NSError *error) { |
| 554 | + }]; |
528 | 555 | } |
529 | | - } else { |
530 | | - RACSignal *signal = [self_weak_ _connectToWirelessDevice:device]; |
531 | | - [signal subscribeNext:^(ECOChannelDeviceInfo * _Nullable x) { |
532 | | - NSLog(@"%@", x); |
533 | | - }]; |
| 556 | + } else if (!isConnected) { |
| 557 | + [self.notConnectWirelessDevices removeObject:device]; |
| 558 | + [self.connectWirelessDevices removeObject:device]; |
| 559 | + [self.channelWillEnd sendNext:device]; |
534 | 560 | } |
535 | | - } else if (!isConnected) { |
536 | | - [self_weak_.notConnectWirelessDevices removeObject:device]; |
537 | | - [self_weak_.connectWirelessDevices removeObject:device]; |
538 | | - [self_weak_.channelWillEnd sendNext:device]; |
539 | | - } |
| 561 | + }); |
540 | 562 | }; |
541 | 563 | // 授权状态变更回调 |
542 | 564 | self.wirelessChannel.authStateChangedBlock = ^(ECOChannelDeviceInfo *device, ECOAuthorizeResponseType authState) { |
543 | | - NSLog(@"🚀 Lookin authStateChangedBlock device:%@", device); |
544 | | - void(^block)(ECOChannelDeviceInfo *device, ECOAuthorizeResponseType authState) = self_weak_.authStateChangedBlocks[@(device.hash)]; |
545 | | - if (block) { |
546 | | - block(device, authState); |
547 | | - } else if (authState && [self_weak_ isWhiteListDevice:device] && ![self_weak_.connectWirelessDevices containsObject:device]) { |
548 | | - [[self_weak_ _tryToConnectToWirelessDevice:device] subscribeNext:^(ECOChannelDeviceInfo * _Nullable x) { |
549 | | - NSLog(@"🚀 Lookin auto connect white list device success. device:%@", x); |
550 | | - }]; |
551 | | - } |
552 | | - if (!authState && [self_weak_.connectWirelessDevices containsObject:device]) { |
553 | | - [self_weak_.connectWirelessDevices removeObject:device]; |
554 | | - [self_weak_.channelWillEnd sendNext:device]; |
555 | | - } |
556 | | - }; |
557 | | - // 请求授权状态认证回调 |
558 | | - self.wirelessChannel.requestAuthBlock = ^(ECOChannelDeviceInfo *device, ECOAuthorizeResponseType authState) { |
559 | | - NSLog(@"🚀 Lookin requestAuthBlock device:%@ authState:%ld", device, authState); |
| 565 | + dispatch_async(dispatch_get_main_queue(), ^{ |
| 566 | + @strongify(self); |
| 567 | + NSString *identifier = LKWirelessDeviceIdentifier(device); |
| 568 | + ECOChannelAuthStateChangedBlock block = identifier.length ? self.authStateChangedBlocks[identifier] : nil; |
| 569 | + if (block) { |
| 570 | + block(device, authState); |
| 571 | + } else if (authState && [self isWhiteListDevice:device] && ![self.connectWirelessDevices containsObject:device]) { |
| 572 | + [[self _tryToConnectToWirelessDevice:device] subscribeNext:^(__unused ECOChannelDeviceInfo *connectedDevice) { |
| 573 | + } error:^(__unused NSError *error) { |
| 574 | + }]; |
| 575 | + } |
| 576 | + if (!authState && [self.connectWirelessDevices containsObject:device]) { |
| 577 | + [self.connectWirelessDevices removeObject:device]; |
| 578 | + [self.channelWillEnd sendNext:device]; |
| 579 | + } |
| 580 | + }); |
560 | 581 | }; |
561 | 582 | } |
562 | 583 |
|
563 | 584 | - (RACSignal<ECOChannelDeviceInfo *> *)_tryToConnectToWirelessDevice:(ECOChannelDeviceInfo *)device { |
564 | | - if (!device.isConnected) |
565 | | - return [RACSignal error:LookinErr_Inner]; |
| 585 | + if (!device.isConnected) { |
| 586 | + NSError *error = [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_Inner userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"Wireless device disconnected.", nil)}]; |
| 587 | + return [RACSignal error:error]; |
| 588 | + } |
| 589 | + |
| 590 | + NSString *identifier = LKWirelessDeviceIdentifier(device); |
| 591 | + if (!identifier.length) { |
| 592 | + NSError *error = [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_Inner userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"Wireless device identity is invalid.", nil)}]; |
| 593 | + return [RACSignal error:error]; |
| 594 | + } |
566 | 595 |
|
567 | 596 | if (!device.authorizedType) { |
568 | 597 | // 未信任 |
569 | 598 | @weakify(self); |
570 | | - RACSignal *signal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { |
571 | | - self_weak_.authStateChangedBlocks[@(device.hash)] = ^(ECOChannelDeviceInfo *device, ECOAuthorizeResponseType authState) { |
| 599 | + RACSignal *authorizationSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { |
| 600 | + @strongify(self); |
| 601 | + if (self.authStateChangedBlocks[identifier]) { |
| 602 | + NSError *error = [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_Inner userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"A wireless connection request is already in progress.", nil)}]; |
| 603 | + [subscriber sendError:error]; |
| 604 | + return nil; |
| 605 | + } |
| 606 | + |
| 607 | + __weak ECOChannelAuthStateChangedBlock weakCallback = nil; |
| 608 | + ECOChannelAuthStateChangedBlock callback = nil; |
| 609 | + callback = [^(ECOChannelDeviceInfo *authorizedDevice, ECOAuthorizeResponseType authState) { |
| 610 | + ECOChannelAuthStateChangedBlock currentCallback = self.authStateChangedBlocks[identifier]; |
| 611 | + if (currentCallback != weakCallback) { |
| 612 | + return; |
| 613 | + } |
| 614 | + [self.authStateChangedBlocks removeObjectForKey:identifier]; |
572 | 615 | if (authState) { |
573 | | - [subscriber sendNext:device]; |
| 616 | + [subscriber sendNext:authorizedDevice]; |
574 | 617 | [subscriber sendCompleted]; |
575 | | - NSLog(@"🚀 Lookin connect device success. device:%@", device); |
576 | 618 | } else { |
577 | | - NSError *error = [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_Inner userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"Wireless Connection rejected", nil)}]; |
578 | | - NSLog(@"🚀 Lookin connect reject. device:%@", device); |
579 | | - dispatch_async(dispatch_get_main_queue(), ^{ |
580 | | - AlertErrorText(NSLocalizedString(@"Wireless Connections", nil), NSLocalizedString(@"Wireless Connection rejected", nil), CurrentKeyWindow); |
581 | | - }); |
| 619 | + NSError *error = [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_Inner userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"Wireless Connection rejected", nil)}]; |
582 | 620 | [subscriber sendError:error]; |
583 | 621 | } |
584 | | - }; |
585 | | - return nil; |
586 | | - }] flattenMap:^__kindof RACSignal * _Nullable(ECOChannelDeviceInfo *device) { |
587 | | - return [self_weak_ _connectToWirelessDevice:device]; |
| 622 | + } copy]; |
| 623 | + weakCallback = callback; |
| 624 | + self.authStateChangedBlocks[identifier] = callback; |
| 625 | + |
| 626 | + BOOL showAuthorizationAlert = ![self.wirelessChannel.whitelistDevices containsObject:identifier]; |
| 627 | + [self.wirelessChannel sendAuthorizationMessageToDevice:device |
| 628 | + state:ECOAuthorizeResponseType_AllowAlways |
| 629 | + showAuthAlert:showAuthorizationAlert]; |
| 630 | + |
| 631 | + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(LKWirelessAuthorizationTimeout * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ |
| 632 | + ECOChannelAuthStateChangedBlock currentCallback = self.authStateChangedBlocks[identifier]; |
| 633 | + if (currentCallback != callback) { |
| 634 | + return; |
| 635 | + } |
| 636 | + [self.authStateChangedBlocks removeObjectForKey:identifier]; |
| 637 | + NSError *error = [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_Inner userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"Wireless connection timed out.", nil)}]; |
| 638 | + [subscriber sendError:error]; |
| 639 | + }); |
| 640 | + |
| 641 | + return [RACDisposable disposableWithBlock:^{ |
| 642 | + dispatch_async(dispatch_get_main_queue(), ^{ |
| 643 | + if (self.authStateChangedBlocks[identifier] == callback) { |
| 644 | + [self.authStateChangedBlocks removeObjectForKey:identifier]; |
| 645 | + } |
| 646 | + }); |
| 647 | + }]; |
| 648 | + }]; |
| 649 | + return [authorizationSignal flattenMap:^__kindof RACSignal * _Nullable(ECOChannelDeviceInfo *authorizedDevice) { |
| 650 | + return [self_weak_ _connectToWirelessDevice:authorizedDevice]; |
588 | 651 | }]; |
589 | | - NSString *uniId = [NSString stringWithFormat:@"%@_%@",device.uuid, device.appInfo.appId]; |
590 | | - [self.wirelessChannel sendAuthorizationMessageToDevice:device |
591 | | - state:ECOAuthorizeResponseType_AllowAlways |
592 | | - showAuthAlert:![self.wirelessChannel.whitelistDevices containsObject:uniId]]; |
593 | | - return signal; |
594 | 652 | } else { |
595 | 653 | return [self _connectToWirelessDevice:device]; |
596 | 654 | } |
|
0 commit comments