@munchi_oy/react-native-label-printer 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -164,48 +164,160 @@ RCT_REMAP_METHOD(checkPrinterAtIp,
164
164
  resolver:(RCTPromiseResolveBlock)resolve
165
165
  rejecter:(RCTPromiseRejectBlock)reject)
166
166
  {
167
- @try {
168
- BRLMChannel *channel = [[BRLMChannel alloc] initWithWifiIPAddress:ipAddress];
169
- if (channel == nil) {
170
- NSMutableDictionary *result = [self errorWithStage:@"channel_create" reason:@"Failed to create BRLMChannel from IP"];
171
- result[@"inputIp"] = ipAddress ?: @"";
172
- resolve(result);
173
- return;
174
- }
167
+ dispatch_async([self labelPrintQueue], ^{
168
+ @try {
169
+ NSInteger maxAttempts = 4;
170
+ NSTimeInterval retryDelay = 1.0;
171
+ NSMutableArray *attemptLogs = [NSMutableArray array];
172
+ NSMutableDictionary *lastFailure = nil;
175
173
 
176
- BRLMPrinterDriverGenerateResult *openResult = [BRLMPrinterDriverGenerator openChannel:channel];
174
+ for (NSInteger attempt = 1; attempt <= maxAttempts; attempt++) {
175
+ id driver = nil;
177
176
 
178
- if (openResult == nil) {
179
- NSMutableDictionary *result = [self errorWithStage:@"open_channel" reason:@"openChannel returned nil"];
180
- result[@"inputIp"] = ipAddress ?: @"";
181
- resolve(result);
182
- return;
183
- }
177
+ @try {
178
+ BRLMChannel *channel = [[BRLMChannel alloc] initWithWifiIPAddress:ipAddress];
179
+ if (channel == nil) {
180
+ lastFailure = [self attemptErrorWithAttempt:attempt
181
+ stage:@"channel_create"
182
+ reason:@"Failed to create BRLMChannel from IP"];
183
+ [attemptLogs addObject:lastFailure];
184
+
185
+ if (attempt < maxAttempts) {
186
+ [NSThread sleepForTimeInterval:retryDelay];
187
+ }
188
+ continue;
189
+ }
190
+
191
+ BRLMPrinterDriverGenerateResult *openResult = [BRLMPrinterDriverGenerator openChannel:channel];
192
+
193
+ NSInteger openChannelCode = 0;
194
+ NSString *openChannelError = @"";
195
+ if (openResult != nil && openResult.error != nil) {
196
+ openChannelCode = openResult.error.code;
197
+ openChannelError = [openResult.error description] ?: @"";
198
+ }
199
+
200
+ if (openResult == nil || openResult.driver == nil) {
201
+ lastFailure = [self attemptErrorWithAttempt:attempt
202
+ stage:@"open_channel"
203
+ reason:@"Failed to open printer driver from channel"
204
+ extras:@{
205
+ @"openChannelCode": @(openChannelCode),
206
+ @"openChannelError": openChannelError
207
+ }];
208
+ [attemptLogs addObject:lastFailure];
209
+
210
+ // warm-up open/close, same idea as print flow
211
+ if (attempt < maxAttempts) {
212
+ @try {
213
+ BRLMChannel *warmupChannel = [[BRLMChannel alloc] initWithWifiIPAddress:ipAddress];
214
+ if (warmupChannel != nil) {
215
+ BRLMPrinterDriverGenerateResult *warmupResult =
216
+ [BRLMPrinterDriverGenerator openChannel:warmupChannel];
217
+
218
+ if (warmupResult != nil && warmupResult.driver != nil) {
219
+ if ([warmupResult.driver respondsToSelector:@selector(closeChannel)]) {
220
+ [warmupResult.driver closeChannel];
221
+ }
222
+ }
223
+ }
224
+ } @catch (NSException *warmupException) {
225
+ }
226
+
227
+ [NSThread sleepForTimeInterval:retryDelay];
228
+ }
229
+ continue;
230
+ }
231
+
232
+ driver = openResult.driver;
233
+
234
+ // settle time after reconnect/open
235
+ [NSThread sleepForTimeInterval:0.8];
236
+
237
+ BRLMGetPrinterStatusResult *statusResult = nil;
238
+ BOOL printerReady = NO;
239
+
240
+ for (NSInteger statusTry = 1; statusTry <= 3; statusTry++) {
241
+ statusResult = [driver getPrinterStatus];
242
+
243
+ if (statusResult != nil && statusResult.status != nil) {
244
+ printerReady = YES;
245
+ break;
246
+ }
247
+
248
+ if (statusTry < 3) {
249
+ [NSThread sleepForTimeInterval:0.7];
250
+ }
251
+ }
252
+
253
+ if (!printerReady) {
254
+ if (driver && [driver respondsToSelector:@selector(closeChannel)]) {
255
+ [driver closeChannel];
256
+ }
257
+
258
+ lastFailure = [self attemptErrorWithAttempt:attempt
259
+ stage:@"get_status"
260
+ reason:@"Failed to get printer status after reconnect"
261
+ extras:@{
262
+ @"statusAvailable": @(statusResult != nil),
263
+ @"statusObjectAvailable": @((statusResult != nil && statusResult.status != nil))
264
+ }];
265
+ [attemptLogs addObject:lastFailure];
266
+
267
+ if (attempt < maxAttempts) {
268
+ [NSThread sleepForTimeInterval:retryDelay];
269
+ }
270
+ continue;
271
+ }
272
+
273
+ NSDictionary *success = @{
274
+ @"ok": @YES,
275
+ @"inputIp": ipAddress ?: @"",
276
+ @"stage": @"open_channel_success",
277
+ @"attempt": @(attempt),
278
+ @"attemptLogs": attemptLogs
279
+ };
280
+
281
+ if (driver && [driver respondsToSelector:@selector(closeChannel)]) {
282
+ [driver closeChannel];
283
+ }
284
+
285
+ resolve(success);
286
+ return;
184
287
 
185
- if (openResult.driver == nil) {
186
- NSMutableDictionary *result = [self errorWithStage:@"open_channel"
187
- reason:@"Failed to open printer driver from channel"
188
- extras:@{ @"openChannelError": openResult.error ? [openResult.error description] : @"" }];
288
+ } @catch (NSException *innerException) {
289
+ if (driver && [driver respondsToSelector:@selector(closeChannel)]) {
290
+ [driver closeChannel];
291
+ }
292
+
293
+ lastFailure = [self attemptErrorWithAttempt:attempt
294
+ stage:@"exception"
295
+ reason:innerException.reason ?: @"Unknown native exception"];
296
+ [attemptLogs addObject:lastFailure];
297
+
298
+ if (attempt < maxAttempts) {
299
+ [NSThread sleepForTimeInterval:retryDelay];
300
+ }
301
+ }
302
+ }
303
+
304
+ NSMutableDictionary *result = [self errorWithStage:@"retry_exhausted"
305
+ reason:@"Printer connection test failed after all recovery attempts"];
189
306
  result[@"inputIp"] = ipAddress ?: @"";
307
+ result[@"attemptLogs"] = attemptLogs;
308
+
309
+ if (lastFailure != nil) {
310
+ result[@"lastFailureStage"] = lastFailure[@"stage"] ?: @"unknown";
311
+ result[@"lastFailureReason"] = lastFailure[@"reason"] ?: @"Unknown error";
312
+ result[@"lastFailureDetails"] = lastFailure;
313
+ }
314
+
190
315
  resolve(result);
191
- return;
192
- }
193
316
 
194
- if ([openResult.driver respondsToSelector:@selector(closeChannel)]) {
195
- [openResult.driver closeChannel];
317
+ } @catch (NSException *exception) {
318
+ reject(@"CHECK_PRINTER_IP_ERROR", exception.reason, nil);
196
319
  }
197
-
198
- resolve(@{
199
- @"ok": @YES,
200
- @"inputIp": ipAddress ?: @"",
201
- @"stage": @"open_channel_success",
202
- @"channelInfo": channel.channelInfo ?: @"",
203
- @"extraInfo": channel.extraInfo ?: @{},
204
- @"driverClass": NSStringFromClass([openResult.driver class])
205
- });
206
- } @catch (NSException *exception) {
207
- reject(@"CHECK_PRINTER_IP_ERROR", exception.reason, nil);
208
- }
320
+ });
209
321
  }
210
322
 
211
323
  RCT_REMAP_METHOD(printLabel,
@@ -246,10 +358,11 @@ RCT_REMAP_METHOD(printLabel,
246
358
  CGFloat titlePointSize = [fontSizes[@"title"] doubleValue];
247
359
  CGFloat bodyPointSize = [fontSizes[@"body"] doubleValue];
248
360
 
249
- NSInteger maxAttempts = 3;
250
- NSTimeInterval retryDelay = 0.35;
361
+ NSInteger maxAttempts = 4;
362
+ NSTimeInterval retryDelay = 1.0;
251
363
  NSMutableArray *attemptLogs = [NSMutableArray array];
252
364
  NSDictionary *finalSuccessResult = nil;
365
+ NSMutableDictionary *lastFailure = nil;
253
366
 
254
367
  for (NSInteger attempt = 1; attempt <= maxAttempts; attempt++) {
255
368
  BRLMChannel *channel = nil;
@@ -258,44 +371,123 @@ RCT_REMAP_METHOD(printLabel,
258
371
  @try {
259
372
  channel = [[BRLMChannel alloc] initWithWifiIPAddress:ipAddress];
260
373
  if (channel == nil) {
261
- [attemptLogs addObject:[self attemptErrorWithAttempt:attempt stage:@"channel_create" reason:@"Failed to create channel"]];
262
- if (attempt < maxAttempts) [NSThread sleepForTimeInterval:retryDelay];
374
+ lastFailure = [self attemptErrorWithAttempt:attempt
375
+ stage:@"channel_create"
376
+ reason:@"Failed to create channel"];
377
+ [attemptLogs addObject:lastFailure];
378
+
379
+ if (attempt < maxAttempts) {
380
+ [NSThread sleepForTimeInterval:retryDelay];
381
+ }
263
382
  continue;
264
383
  }
265
384
 
266
385
  BRLMPrinterDriverGenerateResult *openResult = [BRLMPrinterDriverGenerator openChannel:channel];
267
386
 
387
+ NSInteger openChannelCode = 0;
388
+ NSString *openChannelError = @"";
389
+ if (openResult != nil && openResult.error != nil) {
390
+ openChannelCode = openResult.error.code;
391
+ openChannelError = [openResult.error description] ?: @"";
392
+ }
393
+
268
394
  if (openResult == nil || openResult.driver == nil) {
269
- [attemptLogs addObject:[self attemptErrorWithAttempt:attempt
270
- stage:@"open_channel"
271
- reason:@"Failed to open driver"
272
- extras:@{ @"openChannelError": openResult.error ? [openResult.error description] : @"" }]];
273
- if (attempt < maxAttempts) [NSThread sleepForTimeInterval:retryDelay];
395
+ lastFailure = [self attemptErrorWithAttempt:attempt
396
+ stage:@"open_channel"
397
+ reason:@"Failed to open driver"
398
+ extras:@{
399
+ @"openChannelCode": @(openChannelCode),
400
+ @"openChannelError": openChannelError
401
+ }];
402
+ [attemptLogs addObject:lastFailure];
403
+
404
+
405
+ if (attempt < maxAttempts) {
406
+ @try {
407
+ BRLMChannel *warmupChannel = [[BRLMChannel alloc] initWithWifiIPAddress:ipAddress];
408
+ if (warmupChannel != nil) {
409
+ BRLMPrinterDriverGenerateResult *warmupResult = [BRLMPrinterDriverGenerator openChannel:warmupChannel];
410
+ if (warmupResult != nil && warmupResult.driver != nil) {
411
+ if ([warmupResult.driver respondsToSelector:@selector(closeChannel)]) {
412
+ [warmupResult.driver closeChannel];
413
+ }
414
+ }
415
+ }
416
+ } @catch (NSException *warmupException) {
417
+
418
+ }
419
+
420
+ [NSThread sleepForTimeInterval:retryDelay];
421
+ }
274
422
  continue;
275
423
  }
276
424
 
277
425
  driver = openResult.driver;
278
426
 
279
-
427
+
428
+ [NSThread sleepForTimeInterval:0.8];
429
+
280
430
  BRLMQLPrintSettings *settings = [[BRLMQLPrintSettings alloc] initDefaultPrintSettingsWithPrinterModel:BRLMPrinterModelQL_810W];
281
431
 
282
432
  if (settings == nil) {
283
433
  if ([driver respondsToSelector:@selector(closeChannel)]) {
284
434
  [driver closeChannel];
285
435
  }
286
- [attemptLogs addObject:[self attemptErrorWithAttempt:attempt stage:@"settings_create" reason:@"Failed to create QL print settings"]];
287
- if (attempt < maxAttempts) [NSThread sleepForTimeInterval:retryDelay];
436
+
437
+ lastFailure = [self attemptErrorWithAttempt:attempt
438
+ stage:@"settings_create"
439
+ reason:@"Failed to create QL print settings"];
440
+ [attemptLogs addObject:lastFailure];
441
+
442
+ if (attempt < maxAttempts) {
443
+ [NSThread sleepForTimeInterval:retryDelay];
444
+ }
288
445
  continue;
289
446
  }
290
447
 
291
- BRLMGetPrinterStatusResult *statusResult = [driver getPrinterStatus];
292
- BRLMMediaInfo *mediaInfo = statusResult.status.mediaInfo;
448
+ BRLMGetPrinterStatusResult *statusResult = nil;
449
+ BRLMMediaInfo *mediaInfo = nil;
450
+ BOOL printerReady = NO;
293
451
 
294
- bool succeeded = false;
295
- if (mediaInfo != nil) {
296
- settings.labelSize = [mediaInfo getQLLabelSize:&succeeded];
452
+ for (NSInteger statusTry = 1; statusTry <= 3; statusTry++) {
453
+ statusResult = [driver getPrinterStatus];
454
+
455
+ if (statusResult != nil && statusResult.status != nil) {
456
+ mediaInfo = statusResult.status.mediaInfo;
457
+ if (mediaInfo != nil) {
458
+ printerReady = YES;
459
+ break;
460
+ }
461
+ }
462
+
463
+ if (statusTry < 3) {
464
+ [NSThread sleepForTimeInterval:0.7];
465
+ }
466
+ }
467
+
468
+ if (!printerReady) {
469
+ if ([driver respondsToSelector:@selector(closeChannel)]) {
470
+ [driver closeChannel];
471
+ }
472
+
473
+ lastFailure = [self attemptErrorWithAttempt:attempt
474
+ stage:@"get_status"
475
+ reason:@"Printer status/media not ready after reconnect"
476
+ extras:@{
477
+ @"statusAvailable": @(statusResult != nil),
478
+ @"statusObjectAvailable": @((statusResult != nil && statusResult.status != nil))
479
+ }];
480
+ [attemptLogs addObject:lastFailure];
481
+
482
+ if (attempt < maxAttempts) {
483
+ [NSThread sleepForTimeInterval:retryDelay];
484
+ }
485
+ continue;
297
486
  }
298
487
 
488
+ bool succeeded = false;
489
+ settings.labelSize = [mediaInfo getQLLabelSize:&succeeded];
490
+
299
491
  NSDictionary *mediaExtras = @{
300
492
  @"mediaType": mediaInfo ? @(mediaInfo.mediaType) : [NSNull null],
301
493
  @"width_mm": mediaInfo ? @(mediaInfo.width_mm) : [NSNull null],
@@ -307,11 +499,16 @@ RCT_REMAP_METHOD(printLabel,
307
499
  if ([driver respondsToSelector:@selector(closeChannel)]) {
308
500
  [driver closeChannel];
309
501
  }
310
- [attemptLogs addObject:[self attemptErrorWithAttempt:attempt
311
- stage:@"media_to_label_size"
312
- reason:@"Failed to determine QL label size from loaded media"
313
- extras:mediaExtras]];
314
- if (attempt < maxAttempts) [NSThread sleepForTimeInterval:retryDelay];
502
+
503
+ lastFailure = [self attemptErrorWithAttempt:attempt
504
+ stage:@"media_to_label_size"
505
+ reason:@"Failed to determine QL label size from loaded media"
506
+ extras:mediaExtras];
507
+ [attemptLogs addObject:lastFailure];
508
+
509
+ if (attempt < maxAttempts) {
510
+ [NSThread sleepForTimeInterval:retryDelay];
511
+ }
315
512
  continue;
316
513
  }
317
514
 
@@ -391,12 +588,18 @@ RCT_REMAP_METHOD(printLabel,
391
588
 
392
589
  if (printError != nil && printError.code != BRLMPrintErrorCodeNoError) {
393
590
  NSMutableDictionary *printExtras = [mediaExtras mutableCopy];
591
+ printExtras[@"printErrorCode"] = @(printError.code);
394
592
  printExtras[@"printError"] = [printError description] ?: @"";
395
- [attemptLogs addObject:[self attemptErrorWithAttempt:attempt
396
- stage:@"print"
397
- reason:@"Printer returned print error"
398
- extras:printExtras]];
399
- if (attempt < maxAttempts) [NSThread sleepForTimeInterval:retryDelay];
593
+
594
+ lastFailure = [self attemptErrorWithAttempt:attempt
595
+ stage:@"print"
596
+ reason:@"Printer returned print error"
597
+ extras:printExtras];
598
+ [attemptLogs addObject:lastFailure];
599
+
600
+ if (attempt < maxAttempts) {
601
+ [NSThread sleepForTimeInterval:retryDelay];
602
+ }
400
603
  continue;
401
604
  }
402
605
 
@@ -424,10 +627,15 @@ RCT_REMAP_METHOD(printLabel,
424
627
  if (driver && [driver respondsToSelector:@selector(closeChannel)]) {
425
628
  [driver closeChannel];
426
629
  }
427
- [attemptLogs addObject:[self attemptErrorWithAttempt:attempt
428
- stage:@"exception"
429
- reason:innerException.reason ?: @"Unknown native exception"]];
430
- if (attempt < maxAttempts) [NSThread sleepForTimeInterval:retryDelay];
630
+
631
+ lastFailure = [self attemptErrorWithAttempt:attempt
632
+ stage:@"exception"
633
+ reason:innerException.reason ?: @"Unknown native exception"];
634
+ [attemptLogs addObject:lastFailure];
635
+
636
+ if (attempt < maxAttempts) {
637
+ [NSThread sleepForTimeInterval:retryDelay];
638
+ }
431
639
  }
432
640
  }
433
641
 
@@ -436,13 +644,21 @@ RCT_REMAP_METHOD(printLabel,
436
644
  return;
437
645
  }
438
646
 
439
- NSMutableDictionary *exhaustedResult = [self errorWithStage:@"retry_exhausted" reason:@"Print failed after 3 attempts"];
647
+ NSMutableDictionary *exhaustedResult = [self errorWithStage:@"retry_exhausted"
648
+ reason:@"Print failed after all recovery attempts"];
440
649
  exhaustedResult[@"attemptLogs"] = attemptLogs;
441
650
  exhaustedResult[@"fontSize"] = fontSizeValue ?: @"Medium";
442
651
  exhaustedResult[@"fontStyle"] = fontStyleValue ?: @"Normal";
443
652
  exhaustedResult[@"title"] = title ?: @"";
444
653
  exhaustedResult[@"hideTitle"] = @(hideTitle);
445
654
  exhaustedResult[@"copies"] = @(copies);
655
+
656
+ if (lastFailure != nil) {
657
+ exhaustedResult[@"lastFailureStage"] = lastFailure[@"stage"] ?: @"unknown";
658
+ exhaustedResult[@"lastFailureReason"] = lastFailure[@"reason"] ?: @"Unknown error";
659
+ exhaustedResult[@"lastFailureDetails"] = lastFailure;
660
+ }
661
+
446
662
  resolve(exhaustedResult);
447
663
 
448
664
  } @catch (NSException *exception) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@munchi_oy/react-native-label-printer",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "React Native bridge for label printers",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",