Skip to content

Commit b4cf22f

Browse files
committed
fix: address CodeRabbit review comments
- Add missing newline at EOF in .github/workflows/publish.yml - Replace console.log with proper error handling in buttons.ts - Improve error handling in Zemu.ts close method with try-catch-finally - Add setScrambleKey support to transport proxy for comprehensive error tracking - Remove debugging console.log statements from tests - Remove skipped test that was only for exploration - Replace console.warn with process.stderr.write for cleaner logging
1 parent 8795229 commit b4cf22f

5 files changed

Lines changed: 39 additions & 54 deletions

File tree

.github/workflows/publish.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,5 @@ jobs:
2525
timeout_minutes: 10
2626
dry_run: false
2727
secrets:
28-
NPM_TOKEN: ${{ secrets.NPM_TOKEN_PUBLISH_AUTO }}
28+
NPM_TOKEN: ${{ secrets.NPM_TOKEN_PUBLISH_AUTO }}
29+

src/Zemu.ts

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -191,13 +191,15 @@ export default class Zemu {
191191

192192
static stopAllEmuContainers(): void {
193193
const timer = setTimeout(() => {
194-
console.log('Could not kill all containers before timeout!')
194+
process.stderr.write('Could not kill all containers before timeout!\n')
195195
process.exit(1)
196196
}, KILL_TIMEOUT)
197197

198198
// Clean up pool first
199199
if (Zemu.containerPool) {
200-
Zemu.containerPool.cleanup().catch((error) => console.warn('Failed to cleanup container pool:', error))
200+
Zemu.containerPool.cleanup().catch((error) => {
201+
process.stderr.write(`Failed to cleanup container pool: ${error}\n`)
202+
})
201203
}
202204

203205
// Then kill any remaining containers
@@ -409,31 +411,32 @@ export default class Zemu {
409411
}
410412

411413
async close(): Promise<void> {
412-
try {
413-
this.stopGRPCServer()
414+
this.stopGRPCServer()
414415

416+
try {
415417
if (this.usingPool && this.pooledContainer && Zemu.containerPool) {
416418
this.log('Returning container to pool')
417419
await Zemu.containerPool.release(this.pooledContainer)
418-
this.usingPool = false
419-
this.pooledContainer = null
420420
} else {
421421
this.log('Stopping container')
422422
await this.emuContainer.stop()
423423
}
424424
} catch (error) {
425425
this.log(`Error during close: ${error}`)
426426
// If pool return fails, try to stop container directly
427+
if (this.usingPool && this.emuContainer) {
428+
this.log('Attempting direct container stop after pool release failure')
429+
await this.emuContainer.stop().catch((stopError) => {
430+
this.log(`Failed to stop container directly: ${stopError}`)
431+
})
432+
}
433+
throw error
434+
} finally {
435+
// Always clean up state
427436
if (this.usingPool) {
428-
try {
429-
await this.emuContainer.stop()
430-
} catch (stopError) {
431-
this.log(`Failed to stop container after pool release failure: ${stopError}`)
432-
}
433437
this.usingPool = false
434438
this.pooledContainer = null
435439
}
436-
throw error
437440
}
438441
}
439442

@@ -469,7 +472,7 @@ export default class Zemu {
469472
}
470473
}
471474

472-
// For exchange and other methods, apply similar wrapping
475+
// For exchange method, apply similar wrapping
473476
if (prop === 'exchange') {
474477
return async function (apdu: Buffer) {
475478
try {
@@ -487,6 +490,23 @@ export default class Zemu {
487490
}
488491
}
489492

493+
// For setScrambleKey method, wrap if it exists
494+
if (prop === 'setScrambleKey' && typeof target[prop] === 'function') {
495+
return async function (key: string) {
496+
try {
497+
self.lastTransportError = null
498+
const result = await (target as any).setScrambleKey(key)
499+
return result
500+
} catch (error) {
501+
self.lastTransportError = error as Error
502+
if (isCriticalTransportError(error)) {
503+
self.log(`Critical transport error in setScrambleKey: ${error}`)
504+
}
505+
throw error
506+
}
507+
}
508+
}
509+
490510
// For all other properties/methods, return as-is
491511
return Reflect.get(target, prop, receiver)
492512
},

src/buttons.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { flex } from './buttons_flex'
1818
import { stax } from './buttons_stax'
1919
import { type ButtonKind, type IButton, SwipeDirection, type TModel } from './types'
2020

21-
const dummyButton: IButton = {
21+
const _dummyButton: IButton = {
2222
x: 0,
2323
y: 0,
2424
delay: 0,
@@ -32,23 +32,20 @@ export function getTouchElement(model: TModel, buttonKind: ButtonKind): IButton
3232
if (button != null) {
3333
return button
3434
}
35-
break
35+
throw new Error(`ButtonKind ${buttonKind} not found for model ${model}`)
3636
}
3737

3838
case 'flex': {
3939
const button = flex.TouchElements.get(buttonKind)
4040
if (button != null) {
4141
return button
4242
}
43-
break
43+
throw new Error(`ButtonKind ${buttonKind} not found for model ${model}`)
4444
}
4545

4646
// Add cases for other models here when they become available
4747

4848
default:
49-
return dummyButton
49+
throw new Error(`Unsupported ButtonKind: ${model}, ${buttonKind}`)
5050
}
51-
52-
console.log(`Unsupported ButtonKind: ${model}, ${buttonKind}`)
53-
return dummyButton
5451
}

src/emulator.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ export default class EmuContainer {
5858
docker.listContainers({ all: true, filters: { name: [name] } }, (listError, containers?: ContainerInfo[]) => {
5959
if (listError != null) throw listError
6060
if (containers == null || containers.length === 0) {
61-
console.log('No containers found')
6261
return
6362
}
6463
for (const containerInfo of containers) {

tests/error-handling-simple.test.ts

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,35 +16,6 @@ const ZEMU_OPTIONS_S: IStartOptions = {
1616
}
1717

1818
describe('Error Handling - Simple', () => {
19-
test.skip('First understand current timeout behavior', async () => {
20-
const sim = new Zemu(DEMO_APP_PATH_S)
21-
22-
try {
23-
await sim.start(ZEMU_OPTIONS_S)
24-
const transport = sim.getTransport()
25-
26-
console.log('=== Testing invalid APDU command ===')
27-
28-
// Send an invalid APDU command that should trigger error 0x6984
29-
const startTime = Date.now()
30-
31-
try {
32-
// Invalid CLA (0xFF) should cause error
33-
const result = await transport.send(0xff, 0x00, 0x00, 0x00)
34-
console.log('Result:', result)
35-
} catch (error: any) {
36-
const elapsedTime = Date.now() - startTime
37-
console.log(`Error occurred after ${elapsedTime}ms`)
38-
console.log('Error:', error)
39-
console.log('Error statusCode:', error.statusCode)
40-
console.log('Error name:', error.name)
41-
console.log('Error message:', error.message)
42-
}
43-
} finally {
44-
await sim.close()
45-
}
46-
}, 30000)
47-
4819
test('Test waitUntilScreenIs with timeout', async () => {
4920
// Disable pooling globally for this test
5021
process.env.ZEMU_CONTAINER_POOLING = 'false'
@@ -53,7 +24,6 @@ describe('Error Handling - Simple', () => {
5324

5425
try {
5526
await sim.start(ZEMU_OPTIONS_S)
56-
console.log('=== Testing waitUntilScreenIs behavior ===')
5727

5828
// Get a snapshot that will never match to force timeout
5929
const snapshot = await sim.snapshot()
@@ -71,8 +41,6 @@ describe('Error Handling - Simple', () => {
7141
await sim.waitUntilScreenIs(modifiedSnapshot, 2000)
7242
} catch (error: any) {
7343
const elapsedTime = Date.now() - startTime
74-
console.log(`Timeout occurred after ${elapsedTime}ms`)
75-
console.log('Error message:', error.message)
7644

7745
// Verify it actually waited for the timeout
7846
expect(elapsedTime).toBeGreaterThan(1900)

0 commit comments

Comments
 (0)