Commit b4cb5a44 authored by Tobias's avatar Tobias

more service discovery refactoring

add VLCLocalNetworkServiceBrowser protocol
add VLCLocalNetworkServiceBrowser implementations for NSNetBrowser-based discovery
parent 2771c3ce
/*****************************************************************************
* VLCLocalNetworkService-Protocol.h
* VLC for iOS
*****************************************************************************
* Copyright (c) 2015 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Tobias Conradi <videolan # tobias-conradi.de>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol VLCLocalNetworkService <NSObject>
@required
@property (nonatomic, readonly, nullable) UIImage *icon;
@property (nonatomic, readonly) NSString *title;
@optional
- (nullable UIViewController *)detailViewController;
typedef void (^VLCLocalNetworkServiceActionBlock)(void);
@property (nonatomic, readonly) VLCLocalNetworkServiceActionBlock action;
@end
NS_ASSUME_NONNULL_END
...@@ -9,22 +9,9 @@ ...@@ -9,22 +9,9 @@
* *
* Refer to the COPYING file of the official project for license. * Refer to the COPYING file of the official project for license.
*****************************************************************************/ *****************************************************************************/
#import <Foundation/Foundation.h> #import "VLCLocalNetworkService-Protocol.h"
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@protocol VLCLocalNetworkService <NSObject>
@required
@property (nonatomic, readonly, nullable) UIImage *icon;
@property (nonatomic, readonly) NSString *title;
@optional
- (nullable UIViewController *)detailViewController;
typedef void (^VLCLocalNetworkServiceActionBlock)(void);
@property (nonatomic, readonly) VLCLocalNetworkServiceActionBlock action;
@end
#pragma mark - item #pragma mark - item
@interface VLCLocalNetworkServiceItem : NSObject <VLCLocalNetworkService> @interface VLCLocalNetworkServiceItem : NSObject <VLCLocalNetworkService>
......
/*****************************************************************************
* VLCLocalNetworkServiceBrowser-Protocol.h
* VLC for iOS
*****************************************************************************
* Copyright (c) 2015 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Tobias Conradi <videolan # tobias-conradi.de>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import <Foundation/Foundation.h>
#import "VLCLocalNetworkService.h"
@protocol VLCLocalNetworkServiceBrowserDelegate;
@protocol VLCLocalNetworkServiceBrowser <NSObject>
@property (nonatomic, weak) id <VLCLocalNetworkServiceBrowserDelegate> delegate;
@property (nonatomic, readonly) NSString *name;
@property (nonatomic, readonly) NSUInteger numberOfItems;
- (id<VLCLocalNetworkService>)networkServiceForIndex:(NSUInteger)index;
- (void)startDiscovery;
- (void)stopDiscovery;
@end
@protocol VLCLocalNetworkServiceBrowserDelegate <NSObject>
- (void) localNetworkServiceBrowserDidUpdateServices:(id<VLCLocalNetworkServiceBrowser>)serviceBrowser;
@end
/*****************************************************************************
* VLCLocalNetworkServiceBrowserNetService.h
* VLC for iOS
*****************************************************************************
* Copyright (c) 2015 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Tobias Conradi <videolan # tobias-conradi.de>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import <Foundation/Foundation.h>
#import "VLCLocalNetworkServiceBrowser-Protocol.h"
@interface VLCLocalNetworkServiceBrowserNetService : NSObject <VLCLocalNetworkServiceBrowser>
- (instancetype)initWithName:(NSString *)name serviceType:(NSString *)serviceType domain:(NSString *)domain NS_DESIGNATED_INITIALIZER;
@property (nonatomic, weak) id<VLCLocalNetworkServiceBrowserDelegate> delegate;
@end
@interface VLCLocalNetworkServiceBrowserNetService() <NSNetServiceBrowserDelegate, NSNetServiceDelegate>
@property (nonatomic, readonly) NSNetServiceBrowser *netServiceBrowser;
@property (nonatomic, readonly) NSString *serviceType;
@property (nonatomic, readonly) NSString *domain;
@property (nonatomic, readonly) NSMutableArray<NSNetService*> *rawNetServices;
@property (nonatomic, readonly) NSMutableArray<VLCLocalNetworkServiceNetService*> *resolvedLocalNetworkServices;
// adds netservice and informs delegate
- (void)addResolvedLocalNetworkService:(VLCLocalNetworkServiceNetService *)localNetworkService;
// override in subclasses for different configurations
- (VLCLocalNetworkServiceNetService *)localServiceForNetService:(NSNetService *)netService;
- (void)netServiceDidResolveAddress:(NSNetService *)sender;
@end
#pragma mark - service specific subclasses
@interface VLCLocalNetworkServiceBrowserFTP : VLCLocalNetworkServiceBrowserNetService
- (instancetype)initWithName:(NSString *)name serviceType:(NSString *)serviceType domain:(NSString *)domain NS_UNAVAILABLE;
- (instancetype)init NS_DESIGNATED_INITIALIZER;
@end
@interface VLCLocalNetworkServiceBrowserPlex : VLCLocalNetworkServiceBrowserNetService
- (instancetype)initWithName:(NSString *)name serviceType:(NSString *)serviceType domain:(NSString *)domain NS_UNAVAILABLE;
- (instancetype)init NS_DESIGNATED_INITIALIZER;
@end
@interface VLCLocalNetworkServiceBrowserHTTP : VLCLocalNetworkServiceBrowserNetService
- (instancetype)initWithName:(NSString *)name serviceType:(NSString *)serviceType domain:(NSString *)domain NS_UNAVAILABLE;
- (instancetype)init NS_DESIGNATED_INITIALIZER;
@end
/*****************************************************************************
* VLCLocalNetworkServiceBrowserNetService.m
* VLC for iOS
*****************************************************************************
* Copyright (c) 2015 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Tobias Conradi <videolan # tobias-conradi.de>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import "VLCLocalNetworkServiceBrowserNetService.h"
@interface NSMutableArray(VLCLocalNetworkServiceNetService)
-(NSUInteger)vlc_indexOfServiceWithNetService:(NSNetService*)netService;
-(void)vlc_removeServiceWithNetService:(NSNetService*)netService;
@end
@implementation NSMutableArray (VLCLocalNetworkServiceNetService)
- (NSUInteger)vlc_indexOfServiceWithNetService:(NSNetService *)netService {
NSUInteger index = [self indexOfObjectPassingTest:^BOOL(VLCLocalNetworkServiceNetService *obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (![obj respondsToSelector:@selector(netService)]) return false;
BOOL equal = [obj.netService isEqual:netService];
if (equal) {
*stop = YES;
}
return equal;
}];
return index;
}
-(void)vlc_removeServiceWithNetService:(NSNetService *)netService {
NSUInteger index = [self vlc_indexOfServiceWithNetService:netService];
if (index != NSNotFound) {
[self removeObjectAtIndex:index];
}
}
@end
#pragma mark - NetService based implementation
@implementation VLCLocalNetworkServiceBrowserNetService
@synthesize name = _name;
- (instancetype)initWithName:(NSString *)name serviceType:(NSString *)serviceType domain:(NSString *)domain
{
self = [super init];
if (self) {
_name = name;
_serviceType = serviceType;
_domain = domain;
_netServiceBrowser = [[NSNetServiceBrowser alloc] init];
_netServiceBrowser.delegate = self;
_rawNetServices = [[NSMutableArray alloc] init];
_resolvedLocalNetworkServices = [[NSMutableArray alloc] init];
}
return self;
}
- (instancetype)init {
return [self initWithName:@"" serviceType:@"" domain:@""];
}
- (NSUInteger)numberOfItems {
return self.resolvedLocalNetworkServices.count;
}
- (void)startDiscovery {
[self.netServiceBrowser searchForServicesOfType:self.serviceType inDomain:self.domain];
}
- (void)stopDiscovery {
[self.netServiceBrowser stop];
}
- (id<VLCLocalNetworkService>)networkServiceForIndex:(NSUInteger)index {
return self.resolvedLocalNetworkServices[index];
}
#pragma mark - NSNetServiceBrowserDelegate
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindService:(NSNetService *)service moreComing:(BOOL)moreComing {
APLog(@"found bonjour service: %@ (%@)", service.name, service.type);
[self.rawNetServices addObject:service];
service.delegate = self;
[service resolveWithTimeout:5.];
}
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didRemoveService:(nonnull NSNetService *)service moreComing:(BOOL)moreComing {
APLog(@"bonjour service disappeared: %@ (%i)", service.name, moreComing);
[self.rawNetServices removeObject:service];
[self.resolvedLocalNetworkServices vlc_removeServiceWithNetService:service];
if (!moreComing) {
[self.delegate localNetworkServiceBrowserDidUpdateServices:self];
}
}
#pragma mark - NSNetServiceDelegate
- (void)netServiceDidResolveAddress:(NSNetService *)sender {
VLCLocalNetworkServiceNetService *localNetworkService = [self localServiceForNetService:sender];
[self addResolvedLocalNetworkService:localNetworkService];
}
- (VLCLocalNetworkServiceNetService *)localServiceForNetService:(NSNetService *)netService {
return [[VLCLocalNetworkServiceNetService alloc] initWithNetService:netService];
}
#pragma mark -
- (void)addResolvedLocalNetworkService:(VLCLocalNetworkServiceNetService *)localNetworkService {
if ([self.resolvedLocalNetworkServices vlc_indexOfServiceWithNetService:localNetworkService.netService] != NSNotFound) {
return;
}
[self.resolvedLocalNetworkServices addObject:localNetworkService];
[self.delegate localNetworkServiceBrowserDidUpdateServices:self];
}
@end
#pragma mark - service specific subclasses
@implementation VLCLocalNetworkServiceBrowserFTP
- (instancetype)init {
return [super initWithName:@"File Transfer Protocol (FTP)"
serviceType:@"_ftp._tcp."
domain:@""];
}
- (VLCLocalNetworkServiceNetService *)localServiceForNetService:(NSNetService *)netService {
return [[VLCLocalNetworkServiceFTP alloc] initWithNetService:netService];
}
@end
@implementation VLCLocalNetworkServiceBrowserPlex
- (instancetype)init {
return [super initWithName:@"Plex Media Server (via Bonjour)"
serviceType:@"_plexmediasvr._tcp."
domain:@""];
}
- (VLCLocalNetworkServiceNetService *)localServiceForNetService:(NSNetService *)netService {
return [[VLCLocalNetworkServicePlex alloc] initWithNetService:netService];
}
@end
#import "VLCSharedLibraryParser.h"
@interface VLCLocalNetworkServiceBrowserHTTP()
@property (nonatomic) VLCSharedLibraryParser *httpParser;
@end
@implementation VLCLocalNetworkServiceBrowserHTTP
- (instancetype)init {
return [super initWithName:NSLocalizedString(@"SHARED_VLC_IOS_LIBRARY", nil)
serviceType:@"_http._tcp."
domain:@""];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (VLCSharedLibraryParser *)httpParser {
if (!_httpParser) {
_httpParser = [[VLCSharedLibraryParser alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sharedLibraryFound:)
name:VLCSharedLibraryParserDeterminedNetserviceAsVLCInstance
object:_httpParser];
}
return _httpParser;
}
- (void)netServiceDidResolveAddress:(NSNetService *)sender {
[self.httpParser checkNetserviceForVLCService:sender];
}
- (void)sharedLibraryFound:(NSNotification *)aNotification {
NSNetService *netService = [aNotification.userInfo objectForKey:@"aNetService"];
[self addResolvedLocalNetworkService:[self localServiceForNetService:netService]];
}
- (VLCLocalNetworkServiceNetService *)localServiceForNetService:(NSNetService *)netService {
return [[VLCLocalNetworkServiceHTTP alloc] initWithNetService:netService];
}
@end
...@@ -16,13 +16,13 @@ ...@@ -16,13 +16,13 @@
#import "VLCLocalNetworkService.h" #import "VLCLocalNetworkService.h"
@protocol VLCLocalServerDiscoveryControllerDelegate <NSObject>
@required @protocol VLCLocalServerDiscoveryControllerDelegate <NSObject>
- (void)discoveryFoundSomethingNew; - (void)discoveryFoundSomethingNew;
@end @end
@interface VLCLocalServerDiscoveryController : NSObject @interface VLCLocalServerDiscoveryController : NSObject
@property (nonatomic, readwrite, weak) id delegate; @property (nonatomic, readwrite, weak) id delegate;
......
...@@ -31,8 +31,8 @@ ...@@ -31,8 +31,8 @@
#import "VLCHTTPUploaderController.h" #import "VLCHTTPUploaderController.h"
#import "Reachability.h" #import "Reachability.h"
#import "VLCLocalNetworkServiceBrowserNetService.h"
#define kPlexServiceType @"_plexmediasvr._tcp."
typedef NS_ENUM(NSUInteger, VLCLocalServerSections) { typedef NS_ENUM(NSUInteger, VLCLocalServerSections) {
VLCLocalServerSectionGeneric = 0, VLCLocalServerSectionGeneric = 0,
...@@ -44,46 +44,14 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) { ...@@ -44,46 +44,14 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) {
VLCLocalServerSectionSAP VLCLocalServerSectionSAP
}; };
@interface NSMutableArray(VLCLocalNetworkServiceNetService)
-(NSUInteger)vlc_indexOfServiceWithNetService:(NSNetService*)netService;
-(void)vlc_removeServiceWithNetService:(NSNetService*)netService;
@end
@implementation NSMutableArray (VLCLocalNetworkServiceNetService)
- (NSUInteger)vlc_indexOfServiceWithNetService:(NSNetService *)netService {
NSUInteger index = [self indexOfObjectPassingTest:^BOOL(VLCLocalNetworkServiceNetService *obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (![obj respondsToSelector:@selector(netService)]) return false;
BOOL equal = [obj.netService isEqual:netService];
if (equal) {
*stop = YES;
}
return equal;
}];
return index;
}
-(void)vlc_removeServiceWithNetService:(NSNetService *)netService {
NSUInteger index = [self vlc_indexOfServiceWithNetService:netService];
if (index != NSNotFound) {
[self removeObjectAtIndex:index];
}
}
@end
@interface VLCLocalServerDiscoveryController () <VLCLocalNetworkServiceBrowserDelegate, VLCMediaListDelegate, UPnPDBObserver>
@interface VLCLocalServerDiscoveryController () <NSNetServiceBrowserDelegate, NSNetServiceDelegate, VLCMediaListDelegate, UPnPDBObserver>
{ {
NSNetServiceBrowser *_ftpNetServiceBrowser;
NSNetServiceBrowser *_PlexNetServiceBrowser;
NSNetServiceBrowser *_httpNetServiceBrowser;
NSMutableArray<VLCLocalNetworkServicePlex*> *_plexServices;
NSMutableArray<VLCLocalNetworkServiceHTTP*> *_httpVLCServices;
NSMutableArray<VLCLocalNetworkServiceFTP*> *_ftpServices;
// to keep strong references while resolving id<VLCLocalNetworkServiceBrowser> _plexBrowser;
NSMutableArray *_rawNetServices; id<VLCLocalNetworkServiceBrowser> _FTPBrowser;
id<VLCLocalNetworkServiceBrowser> _HTTPBrowser;
NSArray<VLCLocalNetworkServiceUPnP*> *_filteredUPNPDevices; NSArray<VLCLocalNetworkServiceUPnP*> *_filteredUPNPDevices;
NSArray *_UPNPdevices; NSArray *_UPNPdevices;
...@@ -111,9 +79,7 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) { ...@@ -111,9 +79,7 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) {
[[NSNotificationCenter defaultCenter] removeObserver:self]; [[NSNotificationCenter defaultCenter] removeObserver:self];
[_reachability stopNotifier]; [_reachability stopNotifier];
[_ftpNetServiceBrowser stop]; [self stopDiscovery];
[_PlexNetServiceBrowser stop];
[_httpNetServiceBrowser stop];
} }
- (void)stopDiscovery - (void)stopDiscovery
...@@ -122,16 +88,17 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) { ...@@ -122,16 +88,17 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) {
[self _stopSAPDiscovery]; [self _stopSAPDiscovery];
[self _stopDSMDiscovery]; [self _stopDSMDiscovery];
[_ftpNetServiceBrowser stop]; [_FTPBrowser stopDiscovery];
[_PlexNetServiceBrowser stop]; [_plexBrowser stopDiscovery];
[_httpNetServiceBrowser stop]; [_HTTPBrowser stopDiscovery];
} }
- (void)startDiscovery - (void)startDiscovery
{ {
[_ftpNetServiceBrowser searchForServicesOfType:@"_ftp._tcp." inDomain:@""];
[_PlexNetServiceBrowser searchForServicesOfType:kPlexServiceType inDomain:@""]; [_FTPBrowser startDiscovery];
[_httpNetServiceBrowser searchForServicesOfType:@"_http._tcp." inDomain:@""]; [_plexBrowser startDiscovery];
[_HTTPBrowser startDiscovery];
[self netReachabilityChanged]; [self netReachabilityChanged];
} }
...@@ -140,9 +107,9 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) { ...@@ -140,9 +107,9 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) {
{ {
return @[@"Generic", return @[@"Generic",
@"Universal Plug'n'Play (UPnP)", @"Universal Plug'n'Play (UPnP)",
@"Plex Media Server (via Bonjour)", _plexBrowser.name,
@"File Transfer Protocol (FTP)", _FTPBrowser.name,
NSLocalizedString(@"SHARED_VLC_IOS_LIBRARY", nil), _HTTPBrowser.name,
NSLocalizedString(@"SMB_CIFS_FILE_SERVERS", nil), NSLocalizedString(@"SMB_CIFS_FILE_SERVERS", nil),
@"SAP"]; @"SAP"];
} }
...@@ -165,25 +132,13 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) { ...@@ -165,25 +132,13 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) {
name:UIApplicationDidBecomeActiveNotification name:UIApplicationDidBecomeActiveNotification
object:[UIApplication sharedApplication]]; object:[UIApplication sharedApplication]];
[defaultCenter addObserver:self
selector:@selector(sharedLibraryFound:)
name:VLCSharedLibraryParserDeterminedNetserviceAsVLCInstance
object:nil];
_ftpServices = [[NSMutableArray alloc] init]; _plexBrowser = [[VLCLocalNetworkServiceBrowserPlex alloc] init];
_plexBrowser.delegate = self;
_rawNetServices = [[NSMutableArray alloc] init]; _FTPBrowser = [[VLCLocalNetworkServiceBrowserFTP alloc] init];
_FTPBrowser.delegate = self;
_ftpNetServiceBrowser = [[NSNetServiceBrowser alloc] init]; _HTTPBrowser = [[VLCLocalNetworkServiceBrowserHTTP alloc] init];
_ftpNetServiceBrowser.delegate = self; _HTTPBrowser.delegate = self;
_plexServices = [[NSMutableArray alloc] init];
_PlexNetServiceBrowser = [[NSNetServiceBrowser alloc] init];
_PlexNetServiceBrowser.delegate = self;
_httpVLCServices = [[NSMutableArray alloc] init];
_httpNetServiceBrowser = [[NSNetServiceBrowser alloc] init];
_httpNetServiceBrowser.delegate = self;
_reachability = [Reachability reachabilityForLocalWiFi]; _reachability = [Reachability reachabilityForLocalWiFi];
[_reachability startNotifier]; [_reachability startNotifier];
...@@ -250,17 +205,17 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) { ...@@ -250,17 +205,17 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) {
case VLCLocalServerSectionPlex: case VLCLocalServerSectionPlex:
{ {
return _plexServices[row]; return [_plexBrowser networkServiceForIndex:row];
} }
case VLCLocalServerSectionFTP: case VLCLocalServerSectionFTP:
{ {
return _ftpServices[row]; return [_FTPBrowser networkServiceForIndex:row];
} }
case VLCLocalServerSectionVLCiOS: case VLCLocalServerSectionVLCiOS:
{ {
return _httpVLCServices[row]; return [_HTTPBrowser networkServiceForIndex:row];
} }
case VLCLocalServerSectionSMB: case VLCLocalServerSectionSMB:
...@@ -291,13 +246,13 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) { ...@@ -291,13 +246,13 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) {
return _filteredUPNPDevices.count; return _filteredUPNPDevices.count;
case VLCLocalServerSectionPlex: case VLCLocalServerSectionPlex:
return _plexServices.count; return _plexBrowser.numberOfItems;
case VLCLocalServerSectionFTP: case VLCLocalServerSectionFTP:
return _ftpServices.count; return _FTPBrowser.numberOfItems;
case VLCLocalServerSectionVLCiOS: case VLCLocalServerSectionVLCiOS:
return _httpVLCServices.count; return _HTTPBrowser.numberOfItems;
case VLCLocalServerSectionSMB: case VLCLocalServerSectionSMB:
return _dsmDiscoverer.discoveredMedia.count; return _dsmDiscoverer.discoveredMedia.count;
...@@ -327,82 +282,10 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) { ...@@ -327,82 +282,10 @@ typedef NS_ENUM(NSUInteger, VLCLocalServerSections) {
return YES; return YES;
} }
#pragma mark - bonjour discovery #pragma mark - VLCLocalNetworkServiceBrowserDelegate
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing - (void)localNetworkServiceBrowserDidUpdateServices:(id<VLCLocalNetworkServiceBrowser>)serviceBrowser {
{ if ([self.delegate respondsToSelector:@selector(discoveryFoundSomethingNew)]) {
APLog(@"found bonjour service: %@ (%@)", aNetService.name, aNetService.type); [self.delegate discoveryFoundSomethingNew];