Skip to content

Commit 0abc75d

Browse files
Merge branch 'master' of https://github.com/appium/WebDriverAgent into dependabot/npm_and_yarn/typescript-6.0.2
2 parents b0f49a1 + dd15f48 commit 0abc75d

8 files changed

Lines changed: 166 additions & 46 deletions

File tree

.github/workflows/publish.js.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
with:
5555
xcode-version: "${{ env.XCODE_VERSION }}"
5656
- name: ${{ matrix.config.name }}
57-
uses: nick-fields/retry@v3
57+
uses: nick-fields/retry@v4
5858
with:
5959
timeout_minutes: 10
6060
max_attempts: 3

WebDriverAgentLib/Routing/FBTCPSocket.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ NS_ASSUME_NONNULL_BEGIN
3838

3939
@interface FBTCPSocket : NSObject
4040

41-
@property (nullable, nonatomic) id<FBTCPSocketDelegate> delegate;
41+
#if __has_feature(objc_arc_weak)
42+
@property (nullable, nonatomic, weak) id<FBTCPSocketDelegate> delegate;
43+
#else
44+
@property (nullable, nonatomic, assign) id<FBTCPSocketDelegate> delegate;
45+
#endif
4246

4347
/**
4448
Creates TCP socket isntance which is going to be started on the specified port

WebDriverAgentLib/Routing/FBTCPSocket.m

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,14 @@ - (BOOL)startWithError:(NSError **)error
4848
- (void)stop
4949
{
5050
@synchronized(self.connectedClients) {
51-
for (NSUInteger i = 0; i < [self.connectedClients count]; i++) {
52-
[[self.connectedClients objectAtIndex:i] disconnect];
51+
NSArray *clients = self.connectedClients.copy;
52+
[self.connectedClients removeAllObjects];
53+
for (GCDAsyncSocket *client in clients) {
54+
[client disconnect];
5355
}
5456
}
5557

58+
self.delegate = nil;
5659
[self.listeningSocket disconnect];
5760
}
5861

@@ -66,20 +69,29 @@ - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSo
6669
@synchronized(self.connectedClients) {
6770
[self.connectedClients addObject:newSocket];
6871
}
69-
[self.delegate didClientConnect:newSocket];
72+
id<FBTCPSocketDelegate> delegate = self.delegate;
73+
if (nil != delegate) {
74+
[delegate didClientConnect:newSocket];
75+
}
7076
}
7177

7278
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
7379
{
74-
[self.delegate didClientSendData:sock];
80+
id<FBTCPSocketDelegate> delegate = self.delegate;
81+
if (nil != delegate) {
82+
[delegate didClientSendData:sock];
83+
}
7584
}
7685

7786
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
7887
{
7988
@synchronized(self.connectedClients) {
8089
[self.connectedClients removeObject:sock];
8190
}
82-
[self.delegate didClientDisconnect:sock];
91+
id<FBTCPSocketDelegate> delegate = self.delegate;
92+
if (nil != delegate) {
93+
[delegate didClientDisconnect:sock];
94+
}
8395
}
8496

8597
@end

WebDriverAgentLib/Routing/FBWebServer.m

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,16 @@ @interface FBWebServer ()
4747
@property (nonatomic, strong) RoutingHTTPServer *server;
4848
@property (atomic, assign) BOOL keepAlive;
4949
@property (nonatomic, nullable) FBTCPSocket *screenshotsBroadcaster;
50+
@property (nonatomic, nullable, strong) FBMjpegServer *mjpegServer;
5051
@end
5152

5253
@implementation FBWebServer
5354

55+
- (void)dealloc
56+
{
57+
[self stopScreenshotsBroadcaster];
58+
}
59+
5460
+ (NSArray<Class<FBCommandHandler>> *)collectCommandHandlerClasses
5561
{
5662
NSArray *handlersClasses = FBClassesThatConformsToProtocol(@protocol(FBCommandHandler));
@@ -97,7 +103,7 @@ - (void)startHTTPServer
97103
[self.server setInterface:bindingIP];
98104
[FBLogger logFmt:@"Using custom binding IP address: %@", bindingIP];
99105
}
100-
106+
101107
NSError *error;
102108
BOOL serverStarted = NO;
103109

@@ -117,31 +123,42 @@ - (void)startHTTPServer
117123
[FBLogger logFmt:@"Last attempt to start web server failed with error %@", [error description]];
118124
abort();
119125
}
120-
126+
121127
NSString *serverHost = bindingIP ?: ([XCUIDevice sharedDevice].fb_wifiIPAddress ?: @"127.0.0.1");
122128
[FBLogger logFmt:@"%@http://%@:%d%@", FBServerURLBeginMarker, serverHost, [self.server port], FBServerURLEndMarker];
123129
}
124130

125131
- (void)initScreenshotsBroadcaster
126132
{
127133
[self readMjpegSettingsFromEnv];
134+
self.mjpegServer = [[FBMjpegServer alloc] init];
128135
self.screenshotsBroadcaster = [[FBTCPSocket alloc]
129136
initWithPort:(uint16_t)FBConfiguration.mjpegServerPort];
130-
self.screenshotsBroadcaster.delegate = [[FBMjpegServer alloc] init];
137+
self.screenshotsBroadcaster.delegate = self.mjpegServer;
131138
NSError *error;
132139
if (![self.screenshotsBroadcaster startWithError:&error]) {
133140
[FBLogger logFmt:@"Cannot init screenshots broadcaster service on port %@. Original error: %@", @(FBConfiguration.mjpegServerPort), error.description];
141+
[self.mjpegServer stopStreaming];
142+
self.mjpegServer = nil;
134143
self.screenshotsBroadcaster = nil;
135144
}
136145
}
137146

138147
- (void)stopScreenshotsBroadcaster
139148
{
140149
if (nil == self.screenshotsBroadcaster) {
150+
self.mjpegServer = nil;
141151
return;
142152
}
143153

154+
id<FBTCPSocketDelegate> delegate = self.screenshotsBroadcaster.delegate;
155+
if ([(NSObject *)delegate respondsToSelector:@selector(stopStreaming)]) {
156+
[(FBMjpegServer *)delegate stopStreaming];
157+
}
158+
self.screenshotsBroadcaster.delegate = nil;
144159
[self.screenshotsBroadcaster stop];
160+
self.screenshotsBroadcaster = nil;
161+
self.mjpegServer = nil;
145162
}
146163

147164
- (void)readMjpegSettingsFromEnv
@@ -164,6 +181,8 @@ - (void)stopServing
164181
if (self.server.isRunning) {
165182
[self.server stop:NO];
166183
}
184+
self.server = nil;
185+
self.exceptionHandler = nil;
167186
self.keepAlive = NO;
168187
}
169188

@@ -192,10 +211,15 @@ - (BOOL)attemptToStartServer:(RoutingHTTPServer *)server onPort:(NSInteger)port
192211

193212
- (void)registerRouteHandlers:(NSArray *)commandHandlerClasses
194213
{
214+
__weak typeof(self) weakSelf = self;
195215
for (Class<FBCommandHandler> commandHandler in commandHandlerClasses) {
196216
NSArray *routes = [commandHandler routes];
197217
for (FBRoute *route in routes) {
198218
[self.server handleMethod:route.verb withPath:route.path block:^(RouteRequest *request, RouteResponse *response) {
219+
__strong typeof(weakSelf) strongSelf = weakSelf;
220+
if (nil == strongSelf) {
221+
return;
222+
}
199223
NSDictionary *arguments = [NSJSONSerialization JSONObjectWithData:request.body options:NSJSONReadingMutableContainers error:NULL];
200224
FBRouteRequest *routeParams = [FBRouteRequest
201225
routeRequestWithURL:request.url
@@ -209,7 +233,7 @@ - (void)registerRouteHandlers:(NSArray *)commandHandlerClasses
209233
[route mountRequest:routeParams intoResponse:response];
210234
}
211235
@catch (NSException *exception) {
212-
[self handleException:exception forResponse:response];
236+
[strongSelf handleException:exception forResponse:response];
213237
}
214238
}];
215239
}
@@ -237,9 +261,14 @@ - (void)registerServerKeyRouteHandlers
237261
[response respondWithString:calibrationPage];
238262
}];
239263

264+
__weak typeof(self) weakSelf = self;
240265
[self.server get:@"/wda/shutdown" withBlock:^(RouteRequest *request, RouteResponse *response) {
266+
__strong typeof(weakSelf) strongSelf = weakSelf;
267+
if (nil == strongSelf) {
268+
return;
269+
}
241270
[response respondWithString:@"Shutting down"];
242-
[self.delegate webServerDidRequestShutdown:self];
271+
[strongSelf.delegate webServerDidRequestShutdown:strongSelf];
243272
}];
244273

245274
[self registerRouteHandlers:@[FBUnknownCommands.class]];

WebDriverAgentLib/Utilities/FBImageProcessor.m

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ @interface FBImageProcessor ()
2727
@property (nonatomic) NSData *nextImage;
2828
@property (nonatomic, readonly) NSLock *nextImageLock;
2929
@property (nonatomic, readonly) dispatch_queue_t scalingQueue;
30+
@property (atomic, assign) BOOL isScalingScheduled;
3031

3132
@end
3233

@@ -38,6 +39,7 @@ - (id)init
3839
if (self) {
3940
_nextImageLock = [[NSLock alloc] init];
4041
_scalingQueue = dispatch_queue_create("image.scaling.queue", NULL);
42+
_isScalingScheduled = NO;
4143
}
4244
return self;
4345
}
@@ -51,32 +53,45 @@ - (void)submitImageData:(NSData *)image
5153
[FBLogger verboseLog:@"Discarding screenshot"];
5254
}
5355
self.nextImage = image;
56+
BOOL shouldSchedule = !self.isScalingScheduled;
57+
if (shouldSchedule) {
58+
self.isScalingScheduled = YES;
59+
}
5460
[self.nextImageLock unlock];
61+
if (!shouldSchedule) {
62+
return;
63+
}
5564

5665
#pragma clang diagnostic push
5766
#pragma clang diagnostic ignored "-Wcompletion-handler"
5867
dispatch_async(self.scalingQueue, ^{
59-
[self.nextImageLock lock];
60-
NSData *nextImageData = self.nextImage;
61-
self.nextImage = nil;
62-
[self.nextImageLock unlock];
63-
if (nextImageData == nil) {
64-
return;
65-
}
68+
while (YES) {
69+
@autoreleasepool {
70+
[self.nextImageLock lock];
71+
NSData *nextImageData = self.nextImage;
72+
self.nextImage = nil;
73+
if (nextImageData == nil) {
74+
self.isScalingScheduled = NO;
75+
[self.nextImageLock unlock];
76+
return;
77+
}
78+
[self.nextImageLock unlock];
6679

67-
// We do not want this value to be too high because then we get images larger in size than original ones
68-
// Although, we also don't want to lose too much of the quality on recompression
69-
CGFloat recompressionQuality = MAX(0.9,
70-
MIN(FBMaxCompressionQuality, FBConfiguration.mjpegServerScreenshotQuality / 100.0));
71-
NSData *thumbnailData = [self.class fixedImageDataWithImageData:nextImageData
72-
scalingFactor:scalingFactor
73-
uti:UTTypeJPEG
74-
compressionQuality:recompressionQuality
75-
// iOS always returns screnshots in portrait orientation, but puts the real value into the metadata
76-
// Use it with care. See https://github.com/appium/WebDriverAgent/pull/812
77-
fixOrientation:FBConfiguration.mjpegShouldFixOrientation
78-
desiredOrientation:nil];
79-
completionHandler(thumbnailData ?: nextImageData);
80+
// We do not want this value to be too high because then we get images larger in size than original ones
81+
// Although, we also don't want to lose too much of the quality on recompression
82+
CGFloat recompressionQuality = MAX(0.9,
83+
MIN(FBMaxCompressionQuality, FBConfiguration.mjpegServerScreenshotQuality / 100.0));
84+
NSData *thumbnailData = [self.class fixedImageDataWithImageData:nextImageData
85+
scalingFactor:scalingFactor
86+
uti:UTTypeJPEG
87+
compressionQuality:recompressionQuality
88+
// iOS always returns screenshots in portrait orientation, but puts the real value into the metadata
89+
// Use it with care. See https://github.com/appium/WebDriverAgent/pull/812
90+
fixOrientation:FBConfiguration.mjpegShouldFixOrientation
91+
desiredOrientation:nil];
92+
completionHandler(thumbnailData ?: nextImageData);
93+
}
94+
}
8095
});
8196
#pragma clang diagnostic pop
8297
}

WebDriverAgentLib/Utilities/FBMjpegServer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ NS_ASSUME_NONNULL_BEGIN
1919
*/
2020
- (instancetype)init;
2121

22+
/**
23+
Stops screenshot broadcasting and prevents future scheduling.
24+
*/
25+
- (void)stopStreaming;
26+
2227
@end
2328

2429
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)