123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- #ifdef SHOULD_COMPILE_LOOKIN_SERVER
- //
- // LookinServer.m
- // LookinServer
- //
- // Created by Li Kai on 2018/8/5.
- // https://lookin.work
- //
- #import "LKS_ConnectionManager.h"
- #import "Lookin_PTChannel.h"
- #import "LKS_RequestHandler.h"
- #import "LookinConnectionResponseAttachment.h"
- #import "LKS_ExportManager.h"
- #import "LookinServerDefines.h"
- #import "LKS_TraceManager.h"
- #import "LKS_MultiplatformAdapter.h"
- NSString *const LKS_ConnectionDidEndNotificationName = @"LKS_ConnectionDidEndNotificationName";
- @interface LKS_ConnectionManager () <Lookin_PTChannelDelegate>
- @property(nonatomic, weak) Lookin_PTChannel *peerChannel_;
- @property(nonatomic, strong) LKS_RequestHandler *requestHandler;
- @end
- @implementation LKS_ConnectionManager
- + (instancetype)sharedInstance {
- static LKS_ConnectionManager *sharedInstance;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- sharedInstance = [[LKS_ConnectionManager alloc] init];
- });
- return sharedInstance;
- }
- + (void)load {
- // 触发 init 方法
- [LKS_ConnectionManager sharedInstance];
- }
- - (instancetype)init {
- if (self = [super init]) {
- NSLog(@"LookinServer - Will launch. Framework version: %@", LOOKIN_SERVER_READABLE_VERSION);
-
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleApplicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleWillResignActiveNotification) name:UIApplicationWillResignActiveNotification object:nil];
-
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleLocalInspect:) name:@"Lookin_2D" object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleLocalInspect:) name:@"Lookin_3D" object:nil];
- [[NSNotificationCenter defaultCenter] addObserverForName:@"Lookin_Export" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
- [[LKS_ExportManager sharedInstance] exportAndShare];
- }];
- [[NSNotificationCenter defaultCenter] addObserverForName:@"Lookin_RelationSearch" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
- [[LKS_TraceManager sharedInstance] addSearchTarger:note.object];
- }];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleGetLookinInfo:) name:@"GetLookinInfo" object:nil];
-
- self.requestHandler = [LKS_RequestHandler new];
- }
- return self;
- }
- - (void)_handleWillResignActiveNotification {
- self.applicationIsActive = NO;
-
- if (self.peerChannel_ && ![self.peerChannel_ isConnected]) {
- [self.peerChannel_ close];
- self.peerChannel_ = nil;
- }
- }
- - (void)_handleApplicationDidBecomeActive {
- self.applicationIsActive = YES;
- [self searchPortToListenIfNoConnection];
- }
- - (void)searchPortToListenIfNoConnection {
- if ([self.peerChannel_ isConnected]) {
- NSLog(@"LookinServer - Abort to search ports. Already has connected channel.");
- return;
- }
- NSLog(@"LookinServer - Searching port to listen...");
- [self.peerChannel_ close];
- self.peerChannel_ = nil;
-
- if ([self isiOSAppOnMac]) {
- [self _tryToListenOnPortFrom:LookinSimulatorIPv4PortNumberStart to:LookinSimulatorIPv4PortNumberEnd current:LookinSimulatorIPv4PortNumberStart];
- } else {
- [self _tryToListenOnPortFrom:LookinUSBDeviceIPv4PortNumberStart to:LookinUSBDeviceIPv4PortNumberEnd current:LookinUSBDeviceIPv4PortNumberStart];
- }
- }
- - (BOOL)isiOSAppOnMac {
- #if TARGET_OS_SIMULATOR
- return YES;
- #else
- if (@available(iOS 14.0, *)) {
- // isiOSAppOnMac 这个 API 看似在 iOS 14.0 上可用,但其实在 iOS 14 beta 上是不存在的、有 unrecognized selector 问题,因此这里要用 respondsToSelector 做一下保护
- NSProcessInfo *info = [NSProcessInfo processInfo];
- if ([info respondsToSelector:@selector(isiOSAppOnMac)]) {
- return [info isiOSAppOnMac];
- } else if ([info respondsToSelector:@selector(isMacCatalystApp)]) {
- return [info isMacCatalystApp];
- } else {
- return NO;
- }
- }
- if (@available(iOS 13.0, tvOS 13.0, *)) {
- return [NSProcessInfo processInfo].isMacCatalystApp;
- }
- return NO;
- #endif
- }
- - (void)_tryToListenOnPortFrom:(int)fromPort to:(int)toPort current:(int)currentPort {
- Lookin_PTChannel *channel = [Lookin_PTChannel channelWithDelegate:self];
- channel.targetPort = currentPort;
- [channel listenOnPort:currentPort IPv4Address:INADDR_LOOPBACK callback:^(NSError *error) {
- if (error) {
- if (error.code == 48) {
- // 该地址已被占用
- } else {
- // 未知失败
- }
-
- if (currentPort < toPort) {
- // 尝试下一个端口
- NSLog(@"LookinServer - 127.0.0.1:%d is unavailable(%@). Will try anothor address ...", currentPort, error);
- [self _tryToListenOnPortFrom:fromPort to:toPort current:(currentPort + 1)];
- } else {
- // 所有端口都尝试完毕,全部失败
- NSLog(@"LookinServer - 127.0.0.1:%d is unavailable(%@).", currentPort, error);
- NSLog(@"LookinServer - Connect failed in the end.");
- }
-
- } else {
- // 成功
- NSLog(@"LookinServer - Connected successfully on 127.0.0.1:%d", currentPort);
- // 此时 peerChannel_ 状态为 listening
- self.peerChannel_ = channel;
- }
- }];
- }
- - (void)dealloc {
- if (self.peerChannel_) {
- [self.peerChannel_ close];
- }
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- }
- - (void)respond:(LookinConnectionResponseAttachment *)data requestType:(uint32_t)requestType tag:(uint32_t)tag {
- [self _sendData:data frameOfType:requestType tag:tag];
- }
- - (void)pushData:(NSObject *)data type:(uint32_t)type {
- [self _sendData:data frameOfType:type tag:0];
- }
- - (void)_sendData:(NSObject *)data frameOfType:(uint32_t)frameOfType tag:(uint32_t)tag {
- if (self.peerChannel_) {
- NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:data];
- dispatch_data_t payload = [archivedData createReferencingDispatchData];
-
- [self.peerChannel_ sendFrameOfType:frameOfType tag:tag withPayload:payload callback:^(NSError *error) {
- if (error) {
- }
- }];
- }
- }
- #pragma mark - Lookin_PTChannelDelegate
- - (BOOL)ioFrameChannel:(Lookin_PTChannel*)channel shouldAcceptFrameOfType:(uint32_t)type tag:(uint32_t)tag payloadSize:(uint32_t)payloadSize {
- if (channel != self.peerChannel_) {
- return NO;
- } else if ([self.requestHandler canHandleRequestType:type]) {
- return YES;
- } else {
- [channel close];
- return NO;
- }
- }
- - (void)ioFrameChannel:(Lookin_PTChannel*)channel didReceiveFrameOfType:(uint32_t)type tag:(uint32_t)tag payload:(Lookin_PTData*)payload {
- id object = nil;
- if (payload) {
- id unarchivedObject = [NSKeyedUnarchiver unarchiveObjectWithData:[NSData dataWithContentsOfDispatchData:payload.dispatchData]];
- if ([unarchivedObject isKindOfClass:[LookinConnectionAttachment class]]) {
- LookinConnectionAttachment *attachment = (LookinConnectionAttachment *)unarchivedObject;
- object = attachment.data;
- } else {
- object = unarchivedObject;
- }
- }
- [self.requestHandler handleRequestType:type tag:tag object:object];
- }
- /// 当 Client 端链接成功时,该方法会被调用,然后 channel 的状态会变成 connected
- - (void)ioFrameChannel:(Lookin_PTChannel*)channel didAcceptConnection:(Lookin_PTChannel*)otherChannel fromAddress:(Lookin_PTAddress*)address {
- NSLog(@"LookinServer - channel:%@, acceptConnection:%@", channel.debugTag, otherChannel.debugTag);
- Lookin_PTChannel *previousChannel = self.peerChannel_;
-
- otherChannel.targetPort = address.port;
- self.peerChannel_ = otherChannel;
-
- [previousChannel cancel];
- }
- /// 当连接过 Lookin 客户端,然后 Lookin 客户端又被关闭时,会走到这里
- - (void)ioFrameChannel:(Lookin_PTChannel*)channel didEndWithError:(NSError*)error {
- if (self.peerChannel_ != channel) {
- // Client 端第一次连接上时,之前 listen 的 port 会被 Peertalk 内部 cancel(并在 didAcceptConnection 方法里给业务抛一个新建的 connected 状态的 channel),那个被 cancel 的 channel 会走到这里
- NSLog(@"LookinServer - Ignore channel%@ end.", channel.debugTag);
- return;
- }
- // Client 端关闭时,会走到这里
- NSLog(@"LookinServer - channel%@ DidEndWithError:%@", channel.debugTag, error);
-
- [[NSNotificationCenter defaultCenter] postNotificationName:LKS_ConnectionDidEndNotificationName object:self];
- [self searchPortToListenIfNoConnection];
- }
- #pragma mark - Handler
- - (void)_handleLocalInspect:(NSNotification *)note {
- UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Lookin" message:@"Failed to run local inspection. The feature has been removed. Please use the computer version of Lookin or consider SDKs like FLEX for similar functionality." preferredStyle:UIAlertControllerStyleAlert];
- UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
- [alertController addAction:okAction];
- UIWindow *keyWindow = [LKS_MultiplatformAdapter keyWindow];
- UIViewController *rootViewController = [keyWindow rootViewController];
- [rootViewController presentViewController:alertController animated:YES completion:nil];
-
- NSLog(@"LookinServer - Failed to run local inspection. The feature has been removed. Please use the computer version of Lookin or consider SDKs like FLEX for similar functionality.");
- }
- - (void)handleGetLookinInfo:(NSNotification *)note {
- NSDictionary* userInfo = note.userInfo;
- if (!userInfo) {
- return;
- }
- NSMutableDictionary* infoWrapper = userInfo[@"infos"];
- if (![infoWrapper isKindOfClass:[NSMutableDictionary class]]) {
- NSLog(@"LookinServer - GetLookinInfo failed. Params invalid.");
- return;
- }
- infoWrapper[@"lookinServerVersion"] = LOOKIN_SERVER_READABLE_VERSION;
- }
- @end
- /// 这个类使得用户可以通过 NSClassFromString(@"Lookin") 来判断 LookinServer 是否被编译进了项目里
- @interface Lookin : NSObject
- @end
- @implementation Lookin
- @end
- #endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|