Skip to content

Commit d982c56

Browse files
committed
Fixing WebServerIPhone example
1 parent ae1e2ef commit d982c56

22 files changed

+853
-896
lines changed

Xcode/WebServerIPhone/Classes/MyHTTPConnection.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@
44

55
@interface MyHTTPConnection : HTTPConnection
66

7-
87
@end

Xcode/WebServerIPhone/Classes/MyHTTPConnection.m

Lines changed: 113 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,59 @@
1313

1414
@implementation MyHTTPConnection
1515

16+
static NSMutableSet *webSocketLoggers;
17+
18+
/**
19+
* The runtime sends initialize to each class in a program exactly one time just before the class,
20+
* or any class that inherits from it, is sent its first message from within the program. (Thus the
21+
* method may never be invoked if the class is not used.) The runtime sends the initialize message to
22+
* classes in a thread-safe manner. Superclasses receive this message before their subclasses.
23+
*
24+
* This method may also be called directly (assumably by accident), hence the safety mechanism.
25+
**/
26+
+ (void)initialize
27+
{
28+
static dispatch_once_t onceToken;
29+
dispatch_once(&onceToken, ^{
30+
31+
// We need some place to store the webSocketLogger instances.
32+
// So we'll store them here, in a class variable.
33+
//
34+
// We'll also use a simple notification system to release them when they die.
35+
36+
webSocketLoggers = [[NSMutableSet alloc] init];
37+
38+
[[NSNotificationCenter defaultCenter] addObserver:self
39+
selector:@selector(webSocketLoggerDidDie:)
40+
name:WebSocketLoggerDidDieNotification
41+
object:nil];
42+
});
43+
}
44+
45+
+ (void)addWebSocketLogger:(WebSocketLogger *)webSocketLogger
46+
{
47+
@synchronized(webSocketLoggers)
48+
{
49+
[webSocketLoggers addObject:webSocketLogger];
50+
}
51+
}
52+
53+
+ (void)webSocketLoggerDidDie:(NSNotification *)notification
54+
{
55+
@synchronized(webSocketLoggers)
56+
{
57+
[webSocketLoggers removeObject:[notification object]];
58+
}
59+
}
60+
61+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
62+
#pragma mark Utilities
63+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
64+
65+
/**
66+
* Returns the logFileManager, which is a part of the DDFileLogger system.
67+
* The DDLogFileManager is the subsystem which manages the location and creation of log files.
68+
**/
1669
- (id <DDLogFileManager>)logFileManager
1770
{
1871
WebServerIPhoneAppDelegate *appDelegate;
@@ -21,6 +74,38 @@ @implementation MyHTTPConnection
2174
return appDelegate.fileLogger.logFileManager;
2275
}
2376

77+
/**
78+
* Dynamic discovery of proper websocket href.
79+
**/
80+
- (NSString *)wsLocation
81+
{
82+
NSString *port = [NSString stringWithFormat:@"%hu", [asyncSocket localPort]];
83+
84+
NSString *wsLocation;
85+
NSString *wsHost = [request headerField:@"Host"];
86+
87+
if (wsHost == nil)
88+
{
89+
wsLocation = [NSString stringWithFormat:@"ws://localhost:%@/livelog", port];
90+
}
91+
else
92+
{
93+
wsLocation = [NSString stringWithFormat:@"ws://%@/livelog", wsHost];
94+
}
95+
96+
return wsLocation;
97+
}
98+
99+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
100+
#pragma mark /logs.html
101+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
102+
103+
/**
104+
* Returns the response body for requests to "/logs/index.html".
105+
*
106+
* The response is generated dynamically.
107+
* It returns the list of log files currently on the system, along with their creation date and file size.
108+
**/
24109
- (NSData *)generateIndexData
25110
{
26111
NSArray *sortedLogFileInfos = [[self logFileManager] sortedLogFileInfos];
@@ -83,40 +168,37 @@ - (NSData *)generateIndexData
83168
return [response dataUsingEncoding:NSUTF8StringEncoding];
84169
}
85170

86-
- (NSString *)filePathForURI:(NSString *)path
171+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
172+
#pragma mark HTTPConnection
173+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
174+
175+
/**
176+
* Overrides method in HTTPConnection.
177+
*
178+
* This method is invoked to retrieve the filePath for a given URI.
179+
* We override it to provide proper mapping for log file paths.
180+
**/
181+
- (NSString *)filePathForURI:(NSString *)path allowDirectory:(BOOL)allowDirectory
87182
{
88183
if ([path hasPrefix:@"/logs/"])
89184
{
90185
NSString *logsDir = [[self logFileManager] logsDirectory];
91186
return [logsDir stringByAppendingPathComponent:[path lastPathComponent]];
92187
}
93188

94-
return [super filePathForURI:path];
95-
}
96-
97-
- (NSString *)wsLocation
98-
{
99-
NSString *port = [NSString stringWithFormat:@"%hu", [asyncSocket localPort]];
100-
101-
NSString *wsLocation;
102-
NSString *wsHost = [request headerField:@"Host"];
103-
104-
if (wsHost == nil)
105-
{
106-
wsLocation = [NSString stringWithFormat:@"ws://localhost:%@/livelog", port];
107-
}
108-
else
109-
{
110-
wsLocation = [NSString stringWithFormat:@"ws://%@/livelog", wsHost];
111-
}
112-
113-
return wsLocation;
189+
// Fall through
190+
return [super filePathForURI:path allowDirectory:allowDirectory];
114191
}
115192

193+
/**
194+
* Overrides method in HTTPConnection.
195+
**/
116196
- (NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path
117197
{
118198
if ([path isEqualToString:@"/logs.html"])
119199
{
200+
// Dynamically generate html response with list of available log files
201+
120202
NSData *indexData = [self generateIndexData];
121203
return [[HTTPDataResponse alloc] initWithData:indexData];
122204
}
@@ -139,30 +221,26 @@ - (NSString *)wsLocation
139221
separator:@"%%"
140222
replacementDictionary:replacementDict];
141223
}
142-
else
143-
{
144-
return [super httpResponseForMethod:method URI:path];
145-
}
224+
225+
// Fall through
226+
return [super httpResponseForMethod:method URI:path];
146227
}
147228

229+
/**
230+
* Overrides method in HTTPConnection.
231+
**/
148232
- (WebSocket *)webSocketForURI:(NSString *)path
149233
{
150234
if ([path isEqualToString:@"/livelog"])
151235
{
152236
// Create the WebSocket
153-
WebSocket *ws = [[WebSocket alloc] initWithRequest:request socket:asyncSocket];
237+
WebSocket *webSocket = [[WebSocket alloc] initWithRequest:request socket:asyncSocket];
154238

155239
// Create the WebSocketLogger
156-
WebSocketLogger *wsLogger = [[WebSocketLogger alloc] initWithWebSocket:ws];
157-
158-
// Todo - Broken under ARC. Needs a fix. Commens below from pre-arc.
159-
//
160-
// Memory management:
161-
// The WebSocket will be retained by the HTTPServer and the WebSocketLogger.
162-
// The WebSocketLogger will be retained by the logging framework,
163-
// as it adds itself to the list of active loggers from within its init method.
240+
WebSocketLogger *webSocketLogger = [[WebSocketLogger alloc] initWithWebSocket:webSocket];
164241

165-
return ws;
242+
[[self class] addWebSocketLogger:webSocketLogger];
243+
return webSocket;
166244
}
167245

168246
return [super webSocketForURI:path];

Xcode/WebServerIPhone/Classes/WebSocketLogger.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#import "WebSocket.h"
44

55

6+
#define WebSocketLoggerDidDieNotification @"WebSocketLoggerDidDie"
7+
68
@interface WebSocketLogger : DDAbstractLogger <DDLogger>
79
{
810
WebSocket *websocket;

Xcode/WebServerIPhone/Classes/WebSocketLogger.m

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,13 @@ - (id)initWithWebSocket:(WebSocket *)ws
1212
websocket.delegate = self;
1313

1414
formatter = [[WebSocketFormatter alloc] init];
15-
16-
// Add our logger
17-
//
18-
// We do this here (as opposed to in webSocketDidOpen:) so the logging framework will retain us.
19-
// This is important as nothing else is retaining us.
20-
// It may be a bit hackish, but it's also the simplest solution.
21-
[DDLog addLogger:self];
2215
}
2316
return self;
2417
}
2518

2619
- (void)dealloc
2720
{
2821
[websocket setDelegate:nil];
29-
3022
}
3123

3224
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -38,6 +30,9 @@ - (void)webSocketDidOpen:(WebSocket *)ws
3830
// This method is invoked on the websocketQueue
3931

4032
isWebSocketOpen = YES;
33+
34+
// Add our logger
35+
[DDLog addLogger:self];
4136
}
4237

4338
- (void)webSocketDidClose:(WebSocket *)ws
@@ -48,6 +43,9 @@ - (void)webSocketDidClose:(WebSocket *)ws
4843

4944
// Remove our logger
5045
[DDLog removeLogger:self];
46+
47+
// Post notification
48+
[[NSNotificationCenter defaultCenter] postNotificationName:WebSocketLoggerDidDieNotification object:self];
5149
}
5250

5351
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -73,17 +71,14 @@ - (void)logMessage:(DDLogMessage *)logMessage
7371

7472
if (logMsg)
7573
{
76-
dispatch_async(websocket.websocketQueue, ^{
74+
dispatch_async(websocket.websocketQueue, ^{ @autoreleasepool {
7775

7876
if (isWebSocketOpen)
7977
{
80-
@autoreleasepool {
81-
82-
[websocket sendMessage:logMsg];
78+
[websocket sendMessage:logMsg];
8379

84-
}
8580
}
86-
});
81+
}});
8782
}
8883
}
8984

0 commit comments

Comments
 (0)