diff --git a/GCDWebDAVServer/GCDWebDAVServer.h b/GCDWebDAVServer/GCDWebDAVServer.h index 007829b..7b1e105 100644 --- a/GCDWebDAVServer/GCDWebDAVServer.h +++ b/GCDWebDAVServer/GCDWebDAVServer.h @@ -29,14 +29,15 @@ @class GCDWebDAVServer; -@protocol GCDWebDAVServerDelegate +// These methods are always called on main thread +@protocol GCDWebDAVServerDelegate @optional -- (void)davServer:(GCDWebDAVServer*)uploader didDownloadFileAtPath:(NSString*)path; -- (void)davServer:(GCDWebDAVServer*)uploader didUploadFileAtPath:(NSString*)path; -- (void)davServer:(GCDWebDAVServer*)uploader didMoveItemFromPath:(NSString*)fromPath toPath:(NSString*)toPath; -- (void)davServer:(GCDWebDAVServer*)uploader didCopyItemFromPath:(NSString*)fromPath toPath:(NSString*)toPath; -- (void)davServer:(GCDWebDAVServer*)uploader didDeleteItemAtPath:(NSString*)path; -- (void)davServer:(GCDWebDAVServer*)uploader didCreateDirectoryAtPath:(NSString*)path; +- (void)davServer:(GCDWebDAVServer*)server didDownloadFileAtPath:(NSString*)path; +- (void)davServer:(GCDWebDAVServer*)server didUploadFileAtPath:(NSString*)path; +- (void)davServer:(GCDWebDAVServer*)server didMoveItemFromPath:(NSString*)fromPath toPath:(NSString*)toPath; +- (void)davServer:(GCDWebDAVServer*)server didCopyItemFromPath:(NSString*)fromPath toPath:(NSString*)toPath; +- (void)davServer:(GCDWebDAVServer*)server didDeleteItemAtPath:(NSString*)path; +- (void)davServer:(GCDWebDAVServer*)server didCreateDirectoryAtPath:(NSString*)path; @end @interface GCDWebDAVServer : GCDWebServer diff --git a/GCDWebDAVServer/GCDWebDAVServer.m b/GCDWebDAVServer/GCDWebDAVServer.m index 04ae25f..5a562c1 100644 --- a/GCDWebDAVServer/GCDWebDAVServer.m +++ b/GCDWebDAVServer/GCDWebDAVServer.m @@ -54,7 +54,6 @@ typedef NS_ENUM(NSInteger, DAVProperties) { @interface GCDWebDAVServer () { @private NSString* _uploadDirectory; - id __unsafe_unretained _delegate; NSArray* _allowedExtensions; BOOL _showHidden; } @@ -102,9 +101,9 @@ static inline BOOL _IsMacFinder(GCDWebServerRequest* request) { return [GCDWebServerResponse response]; } - if ([_delegate respondsToSelector:@selector(davServer:didDownloadFileAtPath:)]) { + if ([self.delegate respondsToSelector:@selector(davServer:didDownloadFileAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ - [_delegate davServer:self didDownloadFileAtPath:absolutePath]; + [self.delegate davServer:self didDownloadFileAtPath:absolutePath]; }); } return [GCDWebServerFileResponse responseWithFile:absolutePath]; @@ -145,9 +144,9 @@ static inline BOOL _IsMacFinder(GCDWebServerRequest* request) { return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed moving uploaded file to \"%@\"", relativePath]; } - if ([_delegate respondsToSelector:@selector(davServer:didUploadFileAtPath:)]) { + if ([self.delegate respondsToSelector:@selector(davServer:didUploadFileAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ - [_delegate davServer:self didUploadFileAtPath:absolutePath]; + [self.delegate davServer:self didUploadFileAtPath:absolutePath]; }); } return [GCDWebServerResponse responseWithStatusCode:(existing ? kGCDWebServerHTTPStatusCode_NoContent : kGCDWebServerHTTPStatusCode_Created)]; @@ -180,9 +179,9 @@ static inline BOOL _IsMacFinder(GCDWebServerRequest* request) { return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed deleting \"%@\"", relativePath]; } - if ([_delegate respondsToSelector:@selector(davServer:didDeleteItemAtPath:)]) { + if ([self.delegate respondsToSelector:@selector(davServer:didDeleteItemAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ - [_delegate davServer:self didDeleteItemAtPath:absolutePath]; + [self.delegate davServer:self didDeleteItemAtPath:absolutePath]; }); } return [GCDWebServerResponse responseWithStatusCode:kGCDWebServerHTTPStatusCode_NoContent]; @@ -226,9 +225,9 @@ static inline BOOL _IsMacFinder(GCDWebServerRequest* request) { } #endif - if ([_delegate respondsToSelector:@selector(davServer:didCreateDirectoryAtPath:)]) { + if ([self.delegate respondsToSelector:@selector(davServer:didCreateDirectoryAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ - [_delegate davServer:self didCreateDirectoryAtPath:absolutePath]; + [self.delegate davServer:self didCreateDirectoryAtPath:absolutePath]; }); } return [GCDWebServerResponse responseWithStatusCode:kGCDWebServerHTTPStatusCode_Created]; @@ -298,15 +297,15 @@ static inline BOOL _IsMacFinder(GCDWebServerRequest* request) { } if (isMove) { - if ([_delegate respondsToSelector:@selector(davServer:didMoveItemFromPath:toPath:)]) { + if ([self.delegate respondsToSelector:@selector(davServer:didMoveItemFromPath:toPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ - [_delegate davServer:self didMoveItemFromPath:srcAbsolutePath toPath:dstAbsolutePath]; + [self.delegate davServer:self didMoveItemFromPath:srcAbsolutePath toPath:dstAbsolutePath]; }); } } else { - if ([_delegate respondsToSelector:@selector(davServer:didCopyItemFromPath:toPath:)]) { + if ([self.delegate respondsToSelector:@selector(davServer:didCopyItemFromPath:toPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ - [_delegate davServer:self didCopyItemFromPath:srcAbsolutePath toPath:dstAbsolutePath]; + [self.delegate davServer:self didCopyItemFromPath:srcAbsolutePath toPath:dstAbsolutePath]; }); } } @@ -598,7 +597,7 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name @implementation GCDWebDAVServer -@synthesize uploadDirectory=_uploadDirectory, delegate=_delegate, allowedFileExtensions=_allowedExtensions, showHiddenFiles=_showHidden; +@synthesize uploadDirectory=_uploadDirectory, allowedFileExtensions=_allowedExtensions, showHiddenFiles=_showHidden; - (instancetype)initWithUploadDirectory:(NSString*)path { if ((self = [super init])) { diff --git a/GCDWebServer/Core/GCDWebServer.h b/GCDWebServer/Core/GCDWebServer.h index 5e81d80..c48639d 100644 --- a/GCDWebServer/Core/GCDWebServer.h +++ b/GCDWebServer/Core/GCDWebServer.h @@ -42,7 +42,17 @@ typedef NS_ENUM(int, GCDWebServerLogLevel) { typedef GCDWebServerRequest* (^GCDWebServerMatchBlock)(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery); typedef GCDWebServerResponse* (^GCDWebServerProcessBlock)(GCDWebServerRequest* request); +@class GCDWebServer; + +// These methods are always called on main thread +@protocol GCDWebServerDelegate +@optional +- (void)webServerDidStart:(GCDWebServer*)server; +- (void)webServerDidStop:(GCDWebServer*)server; +@end + @interface GCDWebServer : NSObject +@property(nonatomic, assign) id delegate; @property(nonatomic, readonly, getter=isRunning) BOOL running; @property(nonatomic, readonly) NSUInteger port; @property(nonatomic, readonly) NSString* bonjourName; // Only non-nil if Bonjour registration is active diff --git a/GCDWebServer/Core/GCDWebServer.m b/GCDWebServer/Core/GCDWebServer.m index aed38f9..402f340 100644 --- a/GCDWebServer/Core/GCDWebServer.m +++ b/GCDWebServer/Core/GCDWebServer.m @@ -43,6 +43,7 @@ @interface GCDWebServer () { @private + id __unsafe_unretained _delegate; NSMutableArray* _handlers; NSUInteger _port; @@ -119,7 +120,7 @@ static void _SignalHandler(int signal) { @implementation GCDWebServer -@synthesize handlers=_handlers, port=_port; +@synthesize delegate=_delegate, handlers=_handlers, port=_port; #ifndef __GCDWEBSERVER_LOGGING_HEADER__ @@ -144,6 +145,7 @@ static void _SignalHandler(int signal) { } - (void)dealloc { + _delegate = nil; if (_source) { [self stop]; } @@ -249,7 +251,7 @@ static void _NetServiceClientCallBack(CFNetServiceRef service, CFStreamError* er }); - if (port == 0) { // Determine the actual port we are listening on + if (port == 0) { struct sockaddr addr; socklen_t addrlen = sizeof(addr); if (getsockname(listeningSocket, &addr, &addrlen) == 0) { @@ -277,6 +279,11 @@ static void _NetServiceClientCallBack(CFNetServiceRef service, CFStreamError* er dispatch_resume(_source); LOG_INFO(@"%@ started on port %i and reachable at %@", [self class], (int)_port, self.serverURL); + if ([_delegate respondsToSelector:@selector(webServerDidStart:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [_delegate webServerDidStart:self]; + }); + } } else { LOG_ERROR(@"Failed listening on socket: %s (%i)", strerror(errno), errno); close(listeningSocket); @@ -308,10 +315,15 @@ static void _NetServiceClientCallBack(CFNetServiceRef service, CFStreamError* er dispatch_source_cancel(_source); // This will close the socket ARC_DISPATCH_RELEASE(_source); _source = NULL; + _port = 0; LOG_INFO(@"%@ stopped", [self class]); + if ([_delegate respondsToSelector:@selector(webServerDidStop:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [_delegate webServerDidStop:self]; + }); + } } - _port = 0; } @end diff --git a/GCDWebUploader/GCDWebUploader.h b/GCDWebUploader/GCDWebUploader.h index 30b18c3..91e8b84 100644 --- a/GCDWebUploader/GCDWebUploader.h +++ b/GCDWebUploader/GCDWebUploader.h @@ -29,7 +29,8 @@ @class GCDWebUploader; -@protocol GCDWebUploaderDelegate +// These methods are always called on main thread +@protocol GCDWebUploaderDelegate @optional - (void)webUploader:(GCDWebUploader*)uploader didDownloadFileAtPath:(NSString*)path; - (void)webUploader:(GCDWebUploader*)uploader didUploadFileAtPath:(NSString*)path; diff --git a/GCDWebUploader/GCDWebUploader.m b/GCDWebUploader/GCDWebUploader.m index 466c041..c2edd3b 100644 --- a/GCDWebUploader/GCDWebUploader.m +++ b/GCDWebUploader/GCDWebUploader.m @@ -45,7 +45,6 @@ @interface GCDWebUploader () { @private NSString* _uploadDirectory; - id __unsafe_unretained _delegate; NSArray* _allowedExtensions; BOOL _showHidden; NSString* _title; @@ -143,9 +142,9 @@ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Downlading file name \"%@\" is not allowed", fileName]; } - if ([_delegate respondsToSelector:@selector(webUploader:didDownloadFileAtPath: )]) { + if ([self.delegate respondsToSelector:@selector(webUploader:didDownloadFileAtPath: )]) { dispatch_async(dispatch_get_main_queue(), ^{ - [_delegate webUploader:self didDownloadFileAtPath:absolutePath]; + [self.delegate webUploader:self didDownloadFileAtPath:absolutePath]; }); } return [GCDWebServerFileResponse responseWithFile:absolutePath isAttachment:YES]; @@ -171,9 +170,9 @@ return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed moving uploaded file to \"%@\"", relativePath]; } - if ([_delegate respondsToSelector:@selector(webUploader:didUploadFileAtPath:)]) { + if ([self.delegate respondsToSelector:@selector(webUploader:didUploadFileAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ - [_delegate webUploader:self didUploadFileAtPath:absolutePath]; + [self.delegate webUploader:self didUploadFileAtPath:absolutePath]; }); } return [GCDWebServerDataResponse responseWithJSONObject:@{} contentType:contentType]; @@ -204,9 +203,9 @@ return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed moving \"%@\" to \"%@\"", oldRelativePath, newRelativePath]; } - if ([_delegate respondsToSelector:@selector(webUploader:didMoveItemFromPath:toPath:)]) { + if ([self.delegate respondsToSelector:@selector(webUploader:didMoveItemFromPath:toPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ - [_delegate webUploader:self didMoveItemFromPath:oldAbsolutePath toPath:newAbsolutePath]; + [self.delegate webUploader:self didMoveItemFromPath:oldAbsolutePath toPath:newAbsolutePath]; }); } return [GCDWebServerDataResponse responseWithJSONObject:@{}]; @@ -234,9 +233,9 @@ return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed deleting \"%@\"", relativePath]; } - if ([_delegate respondsToSelector:@selector(webUploader:didDeleteItemAtPath:)]) { + if ([self.delegate respondsToSelector:@selector(webUploader:didDeleteItemAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ - [_delegate webUploader:self didDeleteItemAtPath:absolutePath]; + [self.delegate webUploader:self didDeleteItemAtPath:absolutePath]; }); } return [GCDWebServerDataResponse responseWithJSONObject:@{}]; @@ -260,9 +259,9 @@ return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed creating directory \"%@\"", relativePath]; } - if ([_delegate respondsToSelector:@selector(webUploader:didCreateDirectoryAtPath:)]) { + if ([self.delegate respondsToSelector:@selector(webUploader:didCreateDirectoryAtPath:)]) { dispatch_async(dispatch_get_main_queue(), ^{ - [_delegate webUploader:self didCreateDirectoryAtPath:absolutePath]; + [self.delegate webUploader:self didCreateDirectoryAtPath:absolutePath]; }); } return [GCDWebServerDataResponse responseWithJSONObject:@{}]; @@ -272,7 +271,7 @@ @implementation GCDWebUploader -@synthesize uploadDirectory=_uploadDirectory, delegate=_delegate, allowedFileExtensions=_allowedExtensions, showHiddenFiles=_showHidden, +@synthesize uploadDirectory=_uploadDirectory, allowedFileExtensions=_allowedExtensions, showHiddenFiles=_showHidden, title=_title, header=_header, prologue=_prologue, epilogue=_epilogue, footer=_footer; - (instancetype)initWithUploadDirectory:(NSString*)path {