4444@interface GCDWebServer () {
4545@private
4646 id <GCDWebServerDelegate> __unsafe_unretained _delegate;
47+ dispatch_queue_t _syncQueue;
4748 NSMutableArray * _handlers;
49+ NSInteger _activeConnections; // Accessed only with _syncQueue
50+ BOOL _connected;
51+ CFRunLoopTimerRef _connectedTimer;
4852
4953 NSUInteger _port;
5054 dispatch_source_t _source;
@@ -120,7 +124,7 @@ - (void)dealloc {
120124
121125@implementation GCDWebServer
122126
123- @synthesize delegate=_delegate, handlers=_handlers, port=_port;
127+ @synthesize delegate=_delegate, handlers=_handlers, port=_port, connected=_connected ;
124128
125129#ifndef __GCDWEBSERVER_LOGGING_HEADER__
126130
@@ -137,24 +141,99 @@ + (void)initialize {
137141 GCDWebServerInitializeFunctions ();
138142}
139143
144+ static void _ConnectedTimerCallBack (CFRunLoopTimerRef timer, void * info) {
145+ @autoreleasepool {
146+ [(ARC_BRIDGE GCDWebServer*)info _didDisconnect ];
147+ }
148+ }
149+
140150- (instancetype )init {
141151 if ((self = [super init ])) {
152+ _syncQueue = dispatch_queue_create ([NSStringFromClass ([self class ]) UTF8String ], DISPATCH_QUEUE_SERIAL);
142153 _handlers = [[NSMutableArray alloc ] init ];
154+ CFRunLoopTimerContext context = {0 , (ARC_BRIDGE void *)self, NULL , NULL , NULL };
155+ if ([[self class ] connectedStateCoalescingInterval ] > 0.0 ) {
156+ _connectedTimer = CFRunLoopTimerCreate (kCFAllocatorDefault , HUGE_VAL, HUGE_VAL, 0 , 0 , _ConnectedTimerCallBack, &context);
157+ CFRunLoopAddTimer (CFRunLoopGetMain (), _connectedTimer, kCFRunLoopCommonModes );
158+ }
143159 }
144160 return self;
145161}
146162
147163- (void )dealloc {
164+ DCHECK (_connected == NO );
165+ DCHECK (_activeConnections == 0 );
166+
148167 _delegate = nil ;
149168 if (_source) {
150169 [self stop ];
151170 }
152171
172+ if (_connectedTimer) {
173+ CFRunLoopTimerInvalidate (_connectedTimer);
174+ CFRelease (_connectedTimer);
175+ }
153176 ARC_RELEASE (_handlers);
177+ ARC_DISPATCH_RELEASE (_syncQueue);
154178
155179 ARC_DEALLOC (super);
156180}
157181
182+ - (void )_didConnect {
183+ DCHECK (_connected == NO );
184+ _connected = YES ;
185+ LOG_DEBUG (@" Did connect" );
186+ if ([_delegate respondsToSelector: @selector (webServerDidConnect: )]) {
187+ [_delegate webServerDidConnect: self ];
188+ }
189+ }
190+
191+ // Called from any thread
192+ - (void )willStartConnection : (GCDWebServerConnection*)connection {
193+ dispatch_sync (_syncQueue, ^{
194+
195+ DCHECK (_activeConnections >= 0 );
196+ if (_activeConnections == 0 ) {
197+ dispatch_async (dispatch_get_main_queue (), ^{
198+ if (_connectedTimer) {
199+ CFRunLoopTimerSetNextFireDate (_connectedTimer, HUGE_VAL);
200+ }
201+ if (_connected == NO ) {
202+ [self _didConnect ];
203+ }
204+ });
205+ }
206+ _activeConnections += 1 ;
207+
208+ });
209+ }
210+
211+ - (void )_didDisconnect {
212+ DCHECK (_connected == YES );
213+ _connected = NO ;
214+ LOG_DEBUG (@" Did disconnect" );
215+ if ([_delegate respondsToSelector: @selector (webServerDidDisconnect: )]) {
216+ [_delegate webServerDidDisconnect: self ];
217+ }
218+ }
219+
220+ // Called from any thread
221+ - (void )didEndConnection : (GCDWebServerConnection*)connection {
222+ dispatch_sync (_syncQueue, ^{
223+ DCHECK (_activeConnections > 0 );
224+ _activeConnections -= 1 ;
225+ if (_activeConnections == 0 ) {
226+ dispatch_async (dispatch_get_main_queue (), ^{
227+ if (_connectedTimer) {
228+ CFRunLoopTimerSetNextFireDate (_connectedTimer, CFAbsoluteTimeGetCurrent () + [[self class ] connectedStateCoalescingInterval ]);
229+ } else {
230+ [self _didDisconnect ];
231+ }
232+ });
233+ }
234+ });
235+ }
236+
158237- (NSString *)bonjourName {
159238 CFStringRef name = _service ? CFNetServiceGetName (_service) : NULL ;
160239 return name && CFStringGetLength (name) ? ARC_BRIDGE_RELEASE (CFStringCreateCopy (kCFAllocatorDefault , name)) : nil ;
@@ -346,6 +425,10 @@ + (BOOL)shouldAutomaticallyMapHEADToGET {
346425 return YES ;
347426}
348427
428+ + (NSTimeInterval )connectedStateCoalescingInterval {
429+ return 1.0 ;
430+ }
431+
349432@end
350433
351434@implementation GCDWebServer (Extensions)
0 commit comments