|
26 | 26 | #import <objc/runtime.h> |
27 | 27 | #import <atomic> |
28 | 28 | #import <iostream> |
| 29 | +#import <mutex> |
| 30 | + |
29 | 31 | #import <sstream> |
30 | 32 | #import <vector> |
31 | 33 |
|
@@ -284,44 +286,71 @@ id convertJSIValueToObjCObject( |
284 | 286 | {rt, args[0].getObject(rt).getFunction(rt), std::move(jsInvoker)}); |
285 | 287 | __block std::optional<AsyncCallback<>> reject( |
286 | 288 | {rt, args[1].getObject(rt).getFunction(rt), std::move(jsInvoker)}); |
| 289 | + __block std::shared_ptr<std::mutex> mutex = std::make_shared<std::mutex>(); |
287 | 290 |
|
288 | 291 | RCTPromiseResolveBlock resolveBlock = ^(id result) { |
289 | | - if (!resolve || !reject) { |
290 | | - if (resolveWasCalled) { |
291 | | - RCTLogError(@"%s: Tried to resolve a promise more than once.", moduleMethod.c_str()); |
| 292 | + std::optional<AsyncCallback<>> localResolve; |
| 293 | + bool alreadyResolved = false; |
| 294 | + bool alreadyRejected = false; |
| 295 | + { |
| 296 | + std::lock_guard<std::mutex> lock(*mutex); |
| 297 | + if (!resolve || !reject) { |
| 298 | + alreadyResolved = resolveWasCalled; |
| 299 | + alreadyRejected = !resolveWasCalled; |
292 | 300 | } else { |
293 | | - RCTLogError( |
294 | | - @"%s: Tried to resolve a promise after it's already been rejected.", moduleMethod.c_str()); |
| 301 | + resolveWasCalled = YES; |
| 302 | + localResolve = std::move(resolve); |
| 303 | + resolve = std::nullopt; |
| 304 | + reject = std::nullopt; |
295 | 305 | } |
| 306 | + } |
| 307 | + |
| 308 | + if (alreadyResolved) { |
| 309 | + RCTLogError(@"%s: Tried to resolve a promise more than once.", moduleMethod.c_str()); |
| 310 | + return; |
| 311 | + } |
| 312 | + |
| 313 | + if (alreadyRejected) { |
| 314 | + RCTLogError(@"%s: Tried to resolve a promise after it's already been rejected.", moduleMethod.c_str()); |
296 | 315 | return; |
297 | 316 | } |
298 | 317 |
|
299 | | - resolve->call([result](jsi::Runtime &rt, jsi::Function &jsFunction) { |
| 318 | + localResolve->call([result](jsi::Runtime &rt, jsi::Function &jsFunction) { |
300 | 319 | jsFunction.call(rt, convertObjCObjectToJSIValue(rt, result)); |
301 | 320 | }); |
302 | | - |
303 | | - resolveWasCalled = YES; |
304 | | - resolve = std::nullopt; |
305 | | - reject = std::nullopt; |
306 | 321 | }; |
307 | 322 |
|
308 | 323 | RCTPromiseRejectBlock rejectBlock = ^(NSString *code, NSString *message, NSError *error) { |
309 | | - if (!resolve || !reject) { |
310 | | - if (resolveWasCalled) { |
311 | | - RCTLogError(@"%s: Tried to reject a promise after it's already been resolved.", moduleMethod.c_str()); |
| 324 | + std::optional<AsyncCallback<>> localReject; |
| 325 | + bool alreadyResolved = false; |
| 326 | + bool alreadyRejected = false; |
| 327 | + { |
| 328 | + std::lock_guard<std::mutex> lock(*mutex); |
| 329 | + if (!resolve || !reject) { |
| 330 | + alreadyResolved = resolveWasCalled; |
| 331 | + alreadyRejected = !resolveWasCalled; |
312 | 332 | } else { |
313 | | - RCTLogError(@"%s: Tried to reject a promise more than once.", moduleMethod.c_str()); |
| 333 | + resolveWasCalled = NO; |
| 334 | + localReject = std::move(reject); |
| 335 | + reject = std::nullopt; |
| 336 | + resolve = std::nullopt; |
314 | 337 | } |
| 338 | + } |
| 339 | + |
| 340 | + if (alreadyResolved) { |
| 341 | + RCTLogError(@"%s: Tried to reject a promise after it's already been resolved.", moduleMethod.c_str()); |
| 342 | + return; |
| 343 | + } |
| 344 | + |
| 345 | + if (alreadyRejected) { |
| 346 | + RCTLogError(@"%s: Tried to reject a promise more than once.", moduleMethod.c_str()); |
315 | 347 | return; |
316 | 348 | } |
317 | 349 |
|
318 | 350 | NSDictionary *jsErrorDetails = RCTJSErrorFromCodeMessageAndNSError(code, message, error); |
319 | | - reject->call([jsErrorDetails](jsi::Runtime &rt, jsi::Function &jsFunction) { |
| 351 | + localReject->call([jsErrorDetails](jsi::Runtime &rt, jsi::Function &jsFunction) { |
320 | 352 | jsFunction.call(rt, convertJSErrorDetailsToJSRuntimeError(rt, jsErrorDetails)); |
321 | 353 | }); |
322 | | - resolveWasCalled = NO; |
323 | | - resolve = std::nullopt; |
324 | | - reject = std::nullopt; |
325 | 354 | }; |
326 | 355 |
|
327 | 356 | invokeCopy(resolveBlock, rejectBlock); |
|
0 commit comments