@yume-chan/adb 0.0.9 → 0.0.10
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.
- package/CHANGELOG.json +23 -0
- package/CHANGELOG.md +16 -0
- package/LICENSE +21 -21
- package/README.md +227 -257
- package/dts/adb.d.ts.map +1 -1
- package/dts/auth.d.ts +11 -1
- package/dts/auth.d.ts.map +1 -1
- package/dts/backend.d.ts +3 -5
- package/dts/backend.d.ts.map +1 -1
- package/dts/commands/demo-mode.d.ts +3 -3
- package/dts/commands/demo-mode.d.ts.map +1 -1
- package/dts/commands/reverse.d.ts +2 -2
- package/dts/commands/reverse.d.ts.map +1 -1
- package/dts/commands/shell/index.d.ts +31 -5
- package/dts/commands/shell/index.d.ts.map +1 -1
- package/dts/commands/shell/legacy.d.ts +13 -2
- package/dts/commands/shell/legacy.d.ts.map +1 -1
- package/dts/commands/shell/protocol.d.ts +11 -3
- package/dts/commands/shell/protocol.d.ts.map +1 -1
- package/dts/commands/shell/types.d.ts +35 -3
- package/dts/commands/shell/types.d.ts.map +1 -1
- package/dts/commands/sync/request.d.ts +1 -1
- package/dts/commands/sync/request.d.ts.map +1 -1
- package/dts/commands/sync/response.d.ts +2 -2
- package/dts/commands/sync/response.d.ts.map +1 -1
- package/dts/commands/sync/sync.d.ts.map +1 -1
- package/dts/crypto.d.ts +7 -0
- package/dts/crypto.d.ts.map +1 -1
- package/dts/packet.d.ts.map +1 -1
- package/dts/socket/close-event-emitter.d.ts.map +1 -1
- package/dts/socket/controller.d.ts.map +1 -1
- package/dts/socket/data-event-emitter.d.ts.map +1 -1
- package/dts/socket/dispatcher.d.ts.map +1 -1
- package/dts/stream/buffered-stream.d.ts +2 -4
- package/dts/stream/buffered-stream.d.ts.map +1 -1
- package/dts/utils/encoding.d.ts +3 -0
- package/dts/utils/encoding.d.ts.map +1 -0
- package/dts/utils/index.d.ts +1 -0
- package/dts/utils/index.d.ts.map +1 -1
- package/esm/adb.js +3 -2
- package/esm/adb.js.map +1 -1
- package/esm/auth.js +2 -2
- package/esm/auth.js.map +1 -1
- package/esm/commands/demo-mode.js +9 -9
- package/esm/commands/demo-mode.js.map +1 -1
- package/esm/commands/reverse.js +3 -2
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/shell/index.js +28 -18
- package/esm/commands/shell/index.js.map +1 -1
- package/esm/commands/shell/legacy.js +16 -0
- package/esm/commands/shell/legacy.js.map +1 -1
- package/esm/commands/shell/protocol.js +36 -9
- package/esm/commands/shell/protocol.js.map +1 -1
- package/esm/commands/sync/request.js +5 -4
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.js +4 -3
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/crypto.js +7 -2
- package/esm/crypto.js.map +1 -1
- package/esm/packet.js +12 -14
- package/esm/packet.js.map +1 -1
- package/esm/socket/close-event-emitter.js.map +1 -1
- package/esm/socket/controller.js.map +1 -1
- package/esm/socket/data-event-emitter.js.map +1 -1
- package/esm/socket/dispatcher.js +7 -7
- package/esm/socket/dispatcher.js.map +1 -1
- package/esm/stream/buffered-stream.js +0 -6
- package/esm/stream/buffered-stream.js.map +1 -1
- package/esm/utils/encoding.js +11 -0
- package/esm/utils/encoding.js.map +1 -0
- package/esm/utils/index.js +1 -0
- package/esm/utils/index.js.map +1 -1
- package/package.json +44 -51
- package/src/adb.ts +243 -242
- package/src/auth.ts +166 -156
- package/src/backend.ts +20 -24
- package/src/commands/base.ts +11 -11
- package/src/commands/demo-mode.ts +160 -160
- package/src/commands/framebuffer.ts +73 -73
- package/src/commands/index.ts +8 -8
- package/src/commands/install.ts +21 -21
- package/src/commands/reverse.ts +134 -133
- package/src/commands/shell/index.ts +87 -68
- package/src/commands/shell/legacy.ts +59 -42
- package/src/commands/shell/protocol.ts +121 -94
- package/src/commands/shell/types.ts +55 -21
- package/src/commands/shell/utils.ts +20 -20
- package/src/commands/sync/index.ts +7 -7
- package/src/commands/sync/list.ts +39 -39
- package/src/commands/sync/pull.ts +34 -34
- package/src/commands/sync/push.ts +46 -46
- package/src/commands/sync/request.ts +49 -48
- package/src/commands/sync/response.ts +58 -57
- package/src/commands/sync/stat.ts +121 -121
- package/src/commands/sync/sync.ts +113 -113
- package/src/commands/tcpip.ts +21 -21
- package/src/crypto.ts +285 -280
- package/src/features.ts +5 -5
- package/src/index.ts +10 -10
- package/src/packet.ts +84 -89
- package/src/socket/close-event-emitter.ts +28 -28
- package/src/socket/controller.ts +105 -105
- package/src/socket/data-event-emitter.ts +27 -27
- package/src/socket/dispatcher.ts +269 -269
- package/src/socket/index.ts +6 -6
- package/src/socket/logger.ts +12 -12
- package/src/socket/socket.ts +28 -28
- package/src/stream/buffered-stream.ts +92 -100
- package/src/stream/index.ts +2 -2
- package/src/stream/stream.ts +50 -50
- package/src/utils/auto-reset-event.ts +41 -41
- package/src/utils/base64.ts +274 -274
- package/src/utils/chunk.ts +70 -70
- package/src/utils/encoding.ts +13 -0
- package/src/utils/event-queue.ts +145 -145
- package/src/utils/index.ts +5 -4
- package/cjs/adb.js +0 -205
- package/cjs/adb.js.map +0 -1
- package/cjs/auth.js +0 -141
- package/cjs/auth.js.map +0 -1
- package/cjs/backend.js +0 -3
- package/cjs/backend.js.map +0 -1
- package/cjs/commands/base.js +0 -12
- package/cjs/commands/base.js.map +0 -1
- package/cjs/commands/demo-mode.js +0 -174
- package/cjs/commands/demo-mode.js.map +0 -1
- package/cjs/commands/framebuffer.js +0 -66
- package/cjs/commands/framebuffer.js.map +0 -1
- package/cjs/commands/index.js +0 -12
- package/cjs/commands/index.js.map +0 -1
- package/cjs/commands/install.js +0 -20
- package/cjs/commands/install.js.map +0 -1
- package/cjs/commands/reverse.js +0 -105
- package/cjs/commands/reverse.js.map +0 -1
- package/cjs/commands/shell/index.js +0 -56
- package/cjs/commands/shell/index.js.map +0 -1
- package/cjs/commands/shell/legacy.js +0 -37
- package/cjs/commands/shell/legacy.js.map +0 -1
- package/cjs/commands/shell/protocol.js +0 -83
- package/cjs/commands/shell/protocol.js.map +0 -1
- package/cjs/commands/shell/types.js +0 -3
- package/cjs/commands/shell/types.js.map +0 -1
- package/cjs/commands/shell/utils.js +0 -23
- package/cjs/commands/shell/utils.js.map +0 -1
- package/cjs/commands/sync/index.js +0 -11
- package/cjs/commands/sync/index.js.map +0 -1
- package/cjs/commands/sync/list.js +0 -36
- package/cjs/commands/sync/list.js.map +0 -1
- package/cjs/commands/sync/pull.js +0 -34
- package/cjs/commands/sync/pull.js.map +0 -1
- package/cjs/commands/sync/push.js +0 -49
- package/cjs/commands/sync/push.js.map +0 -1
- package/cjs/commands/sync/request.js +0 -48
- package/cjs/commands/sync/request.js.map +0 -1
- package/cjs/commands/sync/response.js +0 -53
- package/cjs/commands/sync/response.js.map +0 -1
- package/cjs/commands/sync/stat.js +0 -109
- package/cjs/commands/sync/stat.js.map +0 -1
- package/cjs/commands/sync/sync.js +0 -118
- package/cjs/commands/sync/sync.js.map +0 -1
- package/cjs/commands/tcpip.js +0 -28
- package/cjs/commands/tcpip.js.map +0 -1
- package/cjs/crypto.js +0 -231
- package/cjs/crypto.js.map +0 -1
- package/cjs/features.js +0 -10
- package/cjs/features.js.map +0 -1
- package/cjs/index.js +0 -14
- package/cjs/index.js.map +0 -1
- package/cjs/packet.js +0 -77
- package/cjs/packet.js.map +0 -1
- package/cjs/socket/close-event-emitter.js +0 -32
- package/cjs/socket/close-event-emitter.js.map +0 -1
- package/cjs/socket/controller.js +0 -84
- package/cjs/socket/controller.js.map +0 -1
- package/cjs/socket/data-event-emitter.js +0 -29
- package/cjs/socket/data-event-emitter.js.map +0 -1
- package/cjs/socket/dispatcher.js +0 -219
- package/cjs/socket/dispatcher.js.map +0 -1
- package/cjs/socket/index.js +0 -10
- package/cjs/socket/index.js.map +0 -1
- package/cjs/socket/logger.js +0 -3
- package/cjs/socket/logger.js.map +0 -1
- package/cjs/socket/socket.js +0 -24
- package/cjs/socket/socket.js.map +0 -1
- package/cjs/stream/buffered-stream.js +0 -78
- package/cjs/stream/buffered-stream.js.map +0 -1
- package/cjs/stream/index.js +0 -6
- package/cjs/stream/index.js.map +0 -1
- package/cjs/stream/stream.js +0 -45
- package/cjs/stream/stream.js.map +0 -1
- package/cjs/utils/auto-reset-event.js +0 -37
- package/cjs/utils/auto-reset-event.js.map +0 -1
- package/cjs/utils/base64.js +0 -210
- package/cjs/utils/base64.js.map +0 -1
- package/cjs/utils/chunk.js +0 -75
- package/cjs/utils/chunk.js.map +0 -1
- package/cjs/utils/event-queue.js +0 -108
- package/cjs/utils/event-queue.js.map +0 -1
- package/cjs/utils/index.js +0 -8
- package/cjs/utils/index.js.map +0 -1
- package/tsconfig.cjs.json +0 -11
- package/tsconfig.esm.json +0 -28
- package/tsconfig.esm.tsbuildinfo +0 -1305
- package/tsconfig.json +0 -18
package/src/packet.ts
CHANGED
|
@@ -1,89 +1,84 @@
|
|
|
1
|
-
import Struct from '@yume-chan/struct';
|
|
2
|
-
import { AdbBackend } from './backend';
|
|
3
|
-
import { BufferedStream } from './stream';
|
|
4
|
-
|
|
5
|
-
export enum AdbCommand {
|
|
6
|
-
Auth = 0x48545541, // 'AUTH'
|
|
7
|
-
Close = 0x45534c43, // 'CLSE'
|
|
8
|
-
Connect = 0x4e584e43, // 'CNXN'
|
|
9
|
-
OK = 0x59414b4f, // 'OKAY'
|
|
10
|
-
Open = 0x4e45504f, // 'OPEN'
|
|
11
|
-
Write = 0x45545257, // 'WRTE'
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const AdbPacketHeader =
|
|
15
|
-
new Struct({ littleEndian: true })
|
|
16
|
-
.uint32('command')
|
|
17
|
-
.uint32('arg0')
|
|
18
|
-
.uint32('arg1')
|
|
19
|
-
.uint32('payloadLength')
|
|
20
|
-
.uint32('checksum')
|
|
21
|
-
.int32('magic');
|
|
22
|
-
|
|
23
|
-
const AdbPacketStruct =
|
|
24
|
-
new Struct({ littleEndian: true })
|
|
25
|
-
.fields(AdbPacketHeader)
|
|
26
|
-
.arrayBuffer('payload', { lengthField: 'payloadLength' });
|
|
27
|
-
|
|
28
|
-
export type AdbPacket = typeof AdbPacketStruct['TDeserializeResult'];
|
|
29
|
-
|
|
30
|
-
export type AdbPacketInit = Omit<typeof AdbPacketStruct['TInit'], 'checksum' | 'magic'>;
|
|
31
|
-
|
|
32
|
-
export namespace AdbPacket {
|
|
33
|
-
export async function read(backend: AdbBackend): Promise<AdbPacket> {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
init
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
checksum
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (packet.payload.byteLength) {
|
|
86
|
-
await backend.write(packet.payload);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
1
|
+
import Struct from '@yume-chan/struct';
|
|
2
|
+
import { AdbBackend } from './backend';
|
|
3
|
+
import { BufferedStream } from './stream';
|
|
4
|
+
|
|
5
|
+
export enum AdbCommand {
|
|
6
|
+
Auth = 0x48545541, // 'AUTH'
|
|
7
|
+
Close = 0x45534c43, // 'CLSE'
|
|
8
|
+
Connect = 0x4e584e43, // 'CNXN'
|
|
9
|
+
OK = 0x59414b4f, // 'OKAY'
|
|
10
|
+
Open = 0x4e45504f, // 'OPEN'
|
|
11
|
+
Write = 0x45545257, // 'WRTE'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const AdbPacketHeader =
|
|
15
|
+
new Struct({ littleEndian: true })
|
|
16
|
+
.uint32('command')
|
|
17
|
+
.uint32('arg0')
|
|
18
|
+
.uint32('arg1')
|
|
19
|
+
.uint32('payloadLength')
|
|
20
|
+
.uint32('checksum')
|
|
21
|
+
.int32('magic');
|
|
22
|
+
|
|
23
|
+
const AdbPacketStruct =
|
|
24
|
+
new Struct({ littleEndian: true })
|
|
25
|
+
.fields(AdbPacketHeader)
|
|
26
|
+
.arrayBuffer('payload', { lengthField: 'payloadLength' });
|
|
27
|
+
|
|
28
|
+
export type AdbPacket = typeof AdbPacketStruct['TDeserializeResult'];
|
|
29
|
+
|
|
30
|
+
export type AdbPacketInit = Omit<typeof AdbPacketStruct['TInit'], 'checksum' | 'magic'>;
|
|
31
|
+
|
|
32
|
+
export namespace AdbPacket {
|
|
33
|
+
export async function read(backend: AdbBackend): Promise<AdbPacket> {
|
|
34
|
+
// Detect boundary
|
|
35
|
+
// Note that it relies on the backend to only return data from one write operation
|
|
36
|
+
let buffer: ArrayBuffer;
|
|
37
|
+
do {
|
|
38
|
+
// Maybe it's a payload from last connection.
|
|
39
|
+
// Ignore and try again
|
|
40
|
+
buffer = await backend.read(24);
|
|
41
|
+
} while (buffer.byteLength !== 24);
|
|
42
|
+
|
|
43
|
+
let bufferUsed = false;
|
|
44
|
+
const stream = new BufferedStream({
|
|
45
|
+
async read(length: number) {
|
|
46
|
+
if (!bufferUsed) {
|
|
47
|
+
bufferUsed = true;
|
|
48
|
+
return buffer;
|
|
49
|
+
}
|
|
50
|
+
return backend.read(length);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return AdbPacketStruct.deserialize(stream);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function write(
|
|
58
|
+
init: AdbPacketInit,
|
|
59
|
+
calculateChecksum: boolean,
|
|
60
|
+
backend: AdbBackend
|
|
61
|
+
): Promise<void> {
|
|
62
|
+
let checksum: number;
|
|
63
|
+
if (calculateChecksum && init.payload) {
|
|
64
|
+
const array = new Uint8Array(init.payload);
|
|
65
|
+
checksum = array.reduce((result, item) => result + item, 0);
|
|
66
|
+
} else {
|
|
67
|
+
checksum = 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const packet = {
|
|
71
|
+
...init,
|
|
72
|
+
checksum,
|
|
73
|
+
magic: init.command ^ 0xFFFFFFFF,
|
|
74
|
+
payloadLength: init.payload.byteLength,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Write payload separately to avoid an extra copy
|
|
78
|
+
const header = AdbPacketHeader.serialize(packet);
|
|
79
|
+
await backend.write(header);
|
|
80
|
+
if (packet.payload.byteLength) {
|
|
81
|
+
await backend.write(packet.payload);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import { EventEmitter, EventListenerInfo, RemoveEventListener } from '@yume-chan/event';
|
|
2
|
-
|
|
3
|
-
const NoopRemoveEventListener: RemoveEventListener = () => { };
|
|
4
|
-
NoopRemoveEventListener.dispose = NoopRemoveEventListener;
|
|
5
|
-
|
|
6
|
-
export class CloseEventEmitter extends EventEmitter<void, void>{
|
|
7
|
-
private closed = false;
|
|
8
|
-
|
|
9
|
-
protected addEventListener(info: EventListenerInfo<void, void>) {
|
|
10
|
-
if (this.closed) {
|
|
11
|
-
info.listener.apply(info.thisArg, [undefined, ...info.args]);
|
|
12
|
-
return NoopRemoveEventListener;
|
|
13
|
-
} else {
|
|
14
|
-
return super.addEventListener(info);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
public fire() {
|
|
19
|
-
super.fire();
|
|
20
|
-
this.closed = true;
|
|
21
|
-
this.listeners.length = 0;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public dispose() {
|
|
25
|
-
this.fire();
|
|
26
|
-
super.dispose();
|
|
27
|
-
}
|
|
28
|
-
}
|
|
1
|
+
import { EventEmitter, EventListenerInfo, RemoveEventListener } from '@yume-chan/event';
|
|
2
|
+
|
|
3
|
+
const NoopRemoveEventListener: RemoveEventListener = () => { };
|
|
4
|
+
NoopRemoveEventListener.dispose = NoopRemoveEventListener;
|
|
5
|
+
|
|
6
|
+
export class CloseEventEmitter extends EventEmitter<void, void>{
|
|
7
|
+
private closed = false;
|
|
8
|
+
|
|
9
|
+
protected override addEventListener(info: EventListenerInfo<void, void>) {
|
|
10
|
+
if (this.closed) {
|
|
11
|
+
info.listener.apply(info.thisArg, [undefined, ...info.args]);
|
|
12
|
+
return NoopRemoveEventListener;
|
|
13
|
+
} else {
|
|
14
|
+
return super.addEventListener(info);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public override fire() {
|
|
19
|
+
super.fire();
|
|
20
|
+
this.closed = true;
|
|
21
|
+
this.listeners.length = 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public override dispose() {
|
|
25
|
+
this.fire();
|
|
26
|
+
super.dispose();
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/socket/controller.ts
CHANGED
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
import { AutoDisposable } from '@yume-chan/event';
|
|
2
|
-
import { AdbBackend } from '../backend';
|
|
3
|
-
import { AdbCommand } from '../packet';
|
|
4
|
-
import { AutoResetEvent, chunkArrayLike } from '../utils';
|
|
5
|
-
import { CloseEventEmitter } from './close-event-emitter';
|
|
6
|
-
import { DataEventEmitter } from './data-event-emitter';
|
|
7
|
-
import { AdbPacketDispatcher } from './dispatcher';
|
|
8
|
-
|
|
9
|
-
export interface AdbSocketInfo {
|
|
10
|
-
backend: AdbBackend;
|
|
11
|
-
|
|
12
|
-
localId: number;
|
|
13
|
-
|
|
14
|
-
remoteId: number;
|
|
15
|
-
|
|
16
|
-
localCreated: boolean;
|
|
17
|
-
|
|
18
|
-
serviceString: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface AdbSocketConstructionOptions {
|
|
22
|
-
dispatcher: AdbPacketDispatcher;
|
|
23
|
-
|
|
24
|
-
localId: number;
|
|
25
|
-
|
|
26
|
-
remoteId: number;
|
|
27
|
-
|
|
28
|
-
localCreated: boolean;
|
|
29
|
-
|
|
30
|
-
serviceString: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export class AdbSocketController extends AutoDisposable implements AdbSocketInfo {
|
|
34
|
-
private readonly writeChunkLock = this.addDisposable(new AutoResetEvent());
|
|
35
|
-
private readonly writeLock = this.addDisposable(new AutoResetEvent());
|
|
36
|
-
|
|
37
|
-
private readonly dispatcher!: AdbPacketDispatcher;
|
|
38
|
-
public get backend() { return this.dispatcher.backend; }
|
|
39
|
-
|
|
40
|
-
public readonly localId!: number;
|
|
41
|
-
public readonly remoteId!: number;
|
|
42
|
-
public readonly localCreated!: boolean;
|
|
43
|
-
public readonly serviceString!: string;
|
|
44
|
-
|
|
45
|
-
public readonly dataEvent = this.addDisposable(new DataEventEmitter<ArrayBuffer>());
|
|
46
|
-
|
|
47
|
-
private _closed = false;
|
|
48
|
-
public get closed() { return this._closed; }
|
|
49
|
-
|
|
50
|
-
private readonly closeEvent = this.addDisposable(new CloseEventEmitter());
|
|
51
|
-
public get onClose() { return this.closeEvent.event; }
|
|
52
|
-
|
|
53
|
-
public constructor(options: AdbSocketConstructionOptions) {
|
|
54
|
-
super();
|
|
55
|
-
Object.assign(this, options);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
private async writeChunk(data: ArrayBuffer): Promise<void> {
|
|
59
|
-
try {
|
|
60
|
-
// Wait for an ack packet
|
|
61
|
-
await this.writeChunkLock.wait();
|
|
62
|
-
} catch {
|
|
63
|
-
// Lock has been disposed, which means the socket has been closed
|
|
64
|
-
throw new Error('Can not write after closed');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
await this.dispatcher.sendPacket(AdbCommand.Write, this.localId, this.remoteId, data);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
public async write(data: ArrayBuffer): Promise<void> {
|
|
71
|
-
try {
|
|
72
|
-
// Keep write operations in order
|
|
73
|
-
await this.writeLock.wait();
|
|
74
|
-
} catch {
|
|
75
|
-
// Lock has been disposed, which means the socket has been closed
|
|
76
|
-
throw new Error('Can not write after closed');
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
for await (const chunk of chunkArrayLike(data, this.dispatcher.maxPayloadSize)) {
|
|
80
|
-
await this.writeChunk(chunk);
|
|
81
|
-
}
|
|
82
|
-
this.writeLock.notify();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
public ack() {
|
|
86
|
-
this.writeChunkLock.notify();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
public async close(): Promise<void> {
|
|
90
|
-
if (!this._closed) {
|
|
91
|
-
// Immediately cancel all pending writes
|
|
92
|
-
this.writeLock.dispose();
|
|
93
|
-
this.writeChunkLock.dispose();
|
|
94
|
-
|
|
95
|
-
await this.dispatcher.sendPacket(AdbCommand.Close, this.localId, this.remoteId);
|
|
96
|
-
this._closed = true;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
public dispose() {
|
|
101
|
-
this._closed = true;
|
|
102
|
-
this.closeEvent.fire();
|
|
103
|
-
super.dispose();
|
|
104
|
-
}
|
|
105
|
-
}
|
|
1
|
+
import { AutoDisposable } from '@yume-chan/event';
|
|
2
|
+
import { AdbBackend } from '../backend';
|
|
3
|
+
import { AdbCommand } from '../packet';
|
|
4
|
+
import { AutoResetEvent, chunkArrayLike } from '../utils';
|
|
5
|
+
import { CloseEventEmitter } from './close-event-emitter';
|
|
6
|
+
import { DataEventEmitter } from './data-event-emitter';
|
|
7
|
+
import { AdbPacketDispatcher } from './dispatcher';
|
|
8
|
+
|
|
9
|
+
export interface AdbSocketInfo {
|
|
10
|
+
backend: AdbBackend;
|
|
11
|
+
|
|
12
|
+
localId: number;
|
|
13
|
+
|
|
14
|
+
remoteId: number;
|
|
15
|
+
|
|
16
|
+
localCreated: boolean;
|
|
17
|
+
|
|
18
|
+
serviceString: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface AdbSocketConstructionOptions {
|
|
22
|
+
dispatcher: AdbPacketDispatcher;
|
|
23
|
+
|
|
24
|
+
localId: number;
|
|
25
|
+
|
|
26
|
+
remoteId: number;
|
|
27
|
+
|
|
28
|
+
localCreated: boolean;
|
|
29
|
+
|
|
30
|
+
serviceString: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class AdbSocketController extends AutoDisposable implements AdbSocketInfo {
|
|
34
|
+
private readonly writeChunkLock = this.addDisposable(new AutoResetEvent());
|
|
35
|
+
private readonly writeLock = this.addDisposable(new AutoResetEvent());
|
|
36
|
+
|
|
37
|
+
private readonly dispatcher!: AdbPacketDispatcher;
|
|
38
|
+
public get backend() { return this.dispatcher.backend; }
|
|
39
|
+
|
|
40
|
+
public readonly localId!: number;
|
|
41
|
+
public readonly remoteId!: number;
|
|
42
|
+
public readonly localCreated!: boolean;
|
|
43
|
+
public readonly serviceString!: string;
|
|
44
|
+
|
|
45
|
+
public readonly dataEvent = this.addDisposable(new DataEventEmitter<ArrayBuffer>());
|
|
46
|
+
|
|
47
|
+
private _closed = false;
|
|
48
|
+
public get closed() { return this._closed; }
|
|
49
|
+
|
|
50
|
+
private readonly closeEvent = this.addDisposable(new CloseEventEmitter());
|
|
51
|
+
public get onClose() { return this.closeEvent.event; }
|
|
52
|
+
|
|
53
|
+
public constructor(options: AdbSocketConstructionOptions) {
|
|
54
|
+
super();
|
|
55
|
+
Object.assign(this, options);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private async writeChunk(data: ArrayBuffer): Promise<void> {
|
|
59
|
+
try {
|
|
60
|
+
// Wait for an ack packet
|
|
61
|
+
await this.writeChunkLock.wait();
|
|
62
|
+
} catch {
|
|
63
|
+
// Lock has been disposed, which means the socket has been closed
|
|
64
|
+
throw new Error('Can not write after closed');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
await this.dispatcher.sendPacket(AdbCommand.Write, this.localId, this.remoteId, data);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public async write(data: ArrayBuffer): Promise<void> {
|
|
71
|
+
try {
|
|
72
|
+
// Keep write operations in order
|
|
73
|
+
await this.writeLock.wait();
|
|
74
|
+
} catch {
|
|
75
|
+
// Lock has been disposed, which means the socket has been closed
|
|
76
|
+
throw new Error('Can not write after closed');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
for await (const chunk of chunkArrayLike(data, this.dispatcher.maxPayloadSize)) {
|
|
80
|
+
await this.writeChunk(chunk);
|
|
81
|
+
}
|
|
82
|
+
this.writeLock.notify();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public ack() {
|
|
86
|
+
this.writeChunkLock.notify();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public async close(): Promise<void> {
|
|
90
|
+
if (!this._closed) {
|
|
91
|
+
// Immediately cancel all pending writes
|
|
92
|
+
this.writeLock.dispose();
|
|
93
|
+
this.writeChunkLock.dispose();
|
|
94
|
+
|
|
95
|
+
await this.dispatcher.sendPacket(AdbCommand.Close, this.localId, this.remoteId);
|
|
96
|
+
this._closed = true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public override dispose() {
|
|
101
|
+
this._closed = true;
|
|
102
|
+
this.closeEvent.fire();
|
|
103
|
+
super.dispose();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import { PromiseResolver } from '@yume-chan/async';
|
|
2
|
-
import { Event, EventEmitter, EventListenerInfo } from '@yume-chan/event';
|
|
3
|
-
import { ValueOrPromise } from '@yume-chan/struct';
|
|
4
|
-
|
|
5
|
-
export type AsyncEventResult = ValueOrPromise<void>;
|
|
6
|
-
|
|
7
|
-
export type AsyncEvent<TEvent> = Event<TEvent, AsyncEventResult>;
|
|
8
|
-
|
|
9
|
-
export class DataEventEmitter<TEvent> extends EventEmitter<TEvent, AsyncEventResult> {
|
|
10
|
-
private dispatchLock = new PromiseResolver<void>();
|
|
11
|
-
|
|
12
|
-
protected addEventListener(info: EventListenerInfo<TEvent, AsyncEventResult>) {
|
|
13
|
-
const remove = super.addEventListener(info);
|
|
14
|
-
if (this.listeners.length === 1) {
|
|
15
|
-
this.dispatchLock.resolve();
|
|
16
|
-
}
|
|
17
|
-
return remove;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
public async fire(e: TEvent) {
|
|
21
|
-
await this.dispatchLock.promise;
|
|
22
|
-
|
|
23
|
-
for (const info of this.listeners) {
|
|
24
|
-
await info.listener.apply(info.thisArg, [e, ...info.args]);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
1
|
+
import { PromiseResolver } from '@yume-chan/async';
|
|
2
|
+
import { Event, EventEmitter, EventListenerInfo } from '@yume-chan/event';
|
|
3
|
+
import { ValueOrPromise } from '@yume-chan/struct';
|
|
4
|
+
|
|
5
|
+
export type AsyncEventResult = ValueOrPromise<void>;
|
|
6
|
+
|
|
7
|
+
export type AsyncEvent<TEvent> = Event<TEvent, AsyncEventResult>;
|
|
8
|
+
|
|
9
|
+
export class DataEventEmitter<TEvent> extends EventEmitter<TEvent, AsyncEventResult> {
|
|
10
|
+
private dispatchLock = new PromiseResolver<void>();
|
|
11
|
+
|
|
12
|
+
protected override addEventListener(info: EventListenerInfo<TEvent, AsyncEventResult>) {
|
|
13
|
+
const remove = super.addEventListener(info);
|
|
14
|
+
if (this.listeners.length === 1) {
|
|
15
|
+
this.dispatchLock.resolve();
|
|
16
|
+
}
|
|
17
|
+
return remove;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public override async fire(e: TEvent) {
|
|
21
|
+
await this.dispatchLock.promise;
|
|
22
|
+
|
|
23
|
+
for (const info of this.listeners) {
|
|
24
|
+
await info.listener.apply(info.thisArg, [e, ...info.args]);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|