@yume-chan/adb 1.0.0 → 1.1.0
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.md +6 -0
- package/esm/server/client.d.ts +5 -19
- package/esm/server/client.d.ts.map +1 -1
- package/esm/server/client.js +60 -140
- package/esm/server/client.js.map +1 -1
- package/esm/server/index.d.ts +2 -0
- package/esm/server/index.d.ts.map +1 -1
- package/esm/server/index.js +2 -0
- package/esm/server/index.js.map +1 -1
- package/esm/server/observer.d.ts +8 -0
- package/esm/server/observer.d.ts.map +1 -0
- package/esm/server/observer.js +106 -0
- package/esm/server/observer.js.map +1 -0
- package/esm/server/stream.d.ts +19 -0
- package/esm/server/stream.d.ts.map +1 -0
- package/esm/server/stream.js +77 -0
- package/esm/server/stream.js.map +1 -0
- package/esm/server/transport.d.ts +3 -4
- package/esm/server/transport.d.ts.map +1 -1
- package/esm/server/transport.js +16 -14
- package/esm/server/transport.js.map +1 -1
- package/esm/utils/index.d.ts +1 -0
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +1 -0
- package/esm/utils/index.js.map +1 -1
- package/esm/utils/ref.d.ts +18 -0
- package/esm/utils/ref.d.ts.map +1 -0
- package/esm/utils/ref.js +29 -0
- package/esm/utils/ref.js.map +1 -0
- package/package.json +7 -7
- package/src/server/client.ts +86 -172
- package/src/server/index.ts +2 -0
- package/src/server/observer.ts +144 -0
- package/src/server/stream.ts +100 -0
- package/src/server/transport.ts +17 -14
- package/src/utils/index.ts +1 -0
- package/src/utils/ref.ts +37 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { BufferedReadableStream, tryCancel, tryClose, } from "@yume-chan/stream-extra";
|
|
2
|
+
import { bipedal, decodeUtf8, encodeUtf8, TextDecoder, } from "@yume-chan/struct";
|
|
3
|
+
import { hexToNumber, sequenceEqual, write4HexDigits } from "../utils/index.js";
|
|
4
|
+
const OKAY = encodeUtf8("OKAY");
|
|
5
|
+
export const FAIL = encodeUtf8("FAIL");
|
|
6
|
+
export class AdbServerStream {
|
|
7
|
+
#connection;
|
|
8
|
+
#buffered;
|
|
9
|
+
#writer;
|
|
10
|
+
constructor(connection) {
|
|
11
|
+
this.#connection = connection;
|
|
12
|
+
this.#buffered = new BufferedReadableStream(connection.readable);
|
|
13
|
+
this.#writer = connection.writable.getWriter();
|
|
14
|
+
}
|
|
15
|
+
readExactly(length) {
|
|
16
|
+
return this.#buffered.readExactly(length);
|
|
17
|
+
}
|
|
18
|
+
readString = bipedal(function* (then) {
|
|
19
|
+
const data = yield* then(this.readExactly(4));
|
|
20
|
+
const length = hexToNumber(data);
|
|
21
|
+
if (length === 0) {
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
const decoder = new TextDecoder();
|
|
26
|
+
let result = "";
|
|
27
|
+
const iterator = this.#buffered.iterateExactly(length);
|
|
28
|
+
while (true) {
|
|
29
|
+
const { done, value } = iterator.next();
|
|
30
|
+
if (done) {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
result += decoder.decode(yield* then(value), { stream: true });
|
|
34
|
+
}
|
|
35
|
+
result += decoder.decode();
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
async readOkay() {
|
|
40
|
+
const response = await this.readExactly(4);
|
|
41
|
+
if (sequenceEqual(response, OKAY)) {
|
|
42
|
+
// `OKAY` is followed by data length and data
|
|
43
|
+
// But different services want to parse the data differently
|
|
44
|
+
// So don't read the data here
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (sequenceEqual(response, FAIL)) {
|
|
48
|
+
const reason = await this.readString();
|
|
49
|
+
throw new Error(reason);
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`Unexpected response: ${decodeUtf8(response)}`);
|
|
52
|
+
}
|
|
53
|
+
async writeString(value) {
|
|
54
|
+
// TODO: investigate using `encodeUtf8("0000" + value)` then modifying the length
|
|
55
|
+
// That way allocates a new string (hopefully only a rope) instead of a new buffer
|
|
56
|
+
const encoded = encodeUtf8(value);
|
|
57
|
+
const buffer = new Uint8Array(4 + encoded.length);
|
|
58
|
+
write4HexDigits(buffer, 0, encoded.length);
|
|
59
|
+
buffer.set(encoded, 4);
|
|
60
|
+
await this.#writer.write(buffer);
|
|
61
|
+
}
|
|
62
|
+
release() {
|
|
63
|
+
this.#writer.releaseLock();
|
|
64
|
+
return {
|
|
65
|
+
readable: this.#buffered.release(),
|
|
66
|
+
writable: this.#connection.writable,
|
|
67
|
+
closed: this.#connection.closed,
|
|
68
|
+
close: () => this.#connection.close(),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async dispose() {
|
|
72
|
+
void tryCancel(this.#buffered);
|
|
73
|
+
void tryClose(this.#writer);
|
|
74
|
+
await this.#connection.close();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/server/stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { MaybePromiseLike } from "@yume-chan/async";
|
|
2
1
|
import type { AdbIncomingSocketHandler, AdbSocket, AdbTransport } from "../adb.js";
|
|
3
2
|
import type { AdbBanner } from "../banner.js";
|
|
4
3
|
import { AdbFeature } from "../features.js";
|
|
@@ -10,13 +9,13 @@ export declare class AdbServerTransport implements AdbTransport {
|
|
|
10
9
|
readonly transportId: bigint;
|
|
11
10
|
readonly maxPayloadSize: number;
|
|
12
11
|
readonly banner: AdbBanner;
|
|
13
|
-
|
|
12
|
+
get disconnected(): Promise<void>;
|
|
14
13
|
get clientFeatures(): AdbFeature[];
|
|
15
|
-
constructor(client: AdbServerClient, serial: string, banner: AdbBanner, transportId: bigint);
|
|
14
|
+
constructor(client: AdbServerClient, serial: string, banner: AdbBanner, transportId: bigint, disconnected: Promise<void>);
|
|
16
15
|
connect(service: string): Promise<AdbSocket>;
|
|
17
16
|
addReverseTunnel(handler: AdbIncomingSocketHandler, address?: string): Promise<string>;
|
|
18
17
|
removeReverseTunnel(address: string): Promise<void>;
|
|
19
18
|
clearReverseTunnels(): Promise<void>;
|
|
20
|
-
close():
|
|
19
|
+
close(): Promise<void>;
|
|
21
20
|
}
|
|
22
21
|
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/server/transport.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/server/transport.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACR,wBAAwB,EACxB,SAAS,EACT,YAAY,EACf,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,eAAO,MAAM,2BAA2B,EAmBnC,UAAU,EAAE,CAAC;AAElB,qBAAa,kBAAmB,YAAW,YAAY;;IAGnD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAmB;IAElD,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAM3B,IAAI,YAAY,kBAEf;IAED,IAAI,cAAc,iBAIjB;gBAIG,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC;IAUzB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAS5C,gBAAgB,CAClB,OAAO,EAAE,wBAAwB,EACjC,OAAO,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC;IAIZ,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInD,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO/B"}
|
package/esm/server/transport.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { PromiseResolver } from "@yume-chan/async";
|
|
2
|
-
import { AbortController } from "@yume-chan/stream-extra";
|
|
3
2
|
import { AdbFeature } from "../features.js";
|
|
4
3
|
export const ADB_SERVER_DEFAULT_FEATURES = [
|
|
5
4
|
AdbFeature.ShellV2,
|
|
@@ -27,29 +26,29 @@ export class AdbServerTransport {
|
|
|
27
26
|
transportId;
|
|
28
27
|
maxPayloadSize = 1 * 1024 * 1024;
|
|
29
28
|
banner;
|
|
29
|
+
#sockets = [];
|
|
30
30
|
#closed = new PromiseResolver();
|
|
31
|
-
#
|
|
32
|
-
disconnected
|
|
31
|
+
#disconnected;
|
|
32
|
+
get disconnected() {
|
|
33
|
+
return this.#disconnected;
|
|
34
|
+
}
|
|
33
35
|
get clientFeatures() {
|
|
34
36
|
// No need to get host features (features supported by ADB server)
|
|
35
37
|
// Because we create all ADB packets ourselves
|
|
36
38
|
return ADB_SERVER_DEFAULT_FEATURES;
|
|
37
39
|
}
|
|
38
|
-
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
41
|
+
constructor(client, serial, banner, transportId, disconnected) {
|
|
39
42
|
this.#client = client;
|
|
40
43
|
this.serial = serial;
|
|
41
44
|
this.banner = banner;
|
|
42
45
|
this.transportId = transportId;
|
|
43
|
-
this
|
|
44
|
-
this.#closed.promise,
|
|
45
|
-
client.waitFor({ transportId }, "disconnect", {
|
|
46
|
-
signal: this.#waitAbortController.signal,
|
|
47
|
-
unref: true,
|
|
48
|
-
}),
|
|
49
|
-
]);
|
|
46
|
+
this.#disconnected = Promise.race([this.#closed.promise, disconnected]);
|
|
50
47
|
}
|
|
51
48
|
async connect(service) {
|
|
52
|
-
|
|
49
|
+
const socket = await this.#client.createDeviceConnection({ transportId: this.transportId }, service);
|
|
50
|
+
this.#sockets.push(socket);
|
|
51
|
+
return socket;
|
|
53
52
|
}
|
|
54
53
|
async addReverseTunnel(handler, address) {
|
|
55
54
|
return await this.#client.connector.addReverseTunnel(handler, address);
|
|
@@ -60,9 +59,12 @@ export class AdbServerTransport {
|
|
|
60
59
|
async clearReverseTunnels() {
|
|
61
60
|
await this.#client.connector.clearReverseTunnels();
|
|
62
61
|
}
|
|
63
|
-
close() {
|
|
62
|
+
async close() {
|
|
63
|
+
for (const socket of this.#sockets) {
|
|
64
|
+
await socket.close();
|
|
65
|
+
}
|
|
66
|
+
this.#sockets.length = 0;
|
|
64
67
|
this.#closed.resolve();
|
|
65
|
-
this.#waitAbortController.abort();
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
70
|
//# sourceMappingURL=transport.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/server/transport.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/server/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAQnD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAI5C,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACvC,UAAU,CAAC,OAAO;IAClB,UAAU,CAAC,GAAG;IACd,UAAU,CAAC,MAAM;IACjB,UAAU,CAAC,MAAM;IACjB,UAAU,CAAC,cAAc;IACzB,MAAM;IACN,UAAU,CAAC,GAAG;IACd,yFAAyF;IACzF,gCAAgC;IAChC,8BAA8B;IAC9B,UAAU,CAAC,OAAO;IAClB,eAAe;IACf,WAAW;IACX,UAAU,CAAC,aAAa;IACxB,oBAAoB;IACpB,iBAAiB;IACjB,kBAAkB;IAClB,0BAA0B;CACb,CAAC;AAElB,MAAM,OAAO,kBAAkB;IAC3B,OAAO,CAAkB;IAEhB,MAAM,CAAS;IAEf,WAAW,CAAS;IAEpB,cAAc,GAAW,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;IAEzC,MAAM,CAAY;IAE3B,QAAQ,GAAgB,EAAE,CAAC;IAE3B,OAAO,GAAG,IAAI,eAAe,EAAQ,CAAC;IACtC,aAAa,CAAgB;IAC7B,IAAI,YAAY;QACZ,OAAO,IAAI,CAAC,aAAa,CAAC;IAC9B,CAAC;IAED,IAAI,cAAc;QACd,kEAAkE;QAClE,8CAA8C;QAC9C,OAAO,2BAA2B,CAAC;IACvC,CAAC;IAED,yDAAyD;IACzD,YACI,MAAuB,EACvB,MAAc,EACd,MAAiB,EACjB,WAAmB,EACnB,YAA2B;QAE3B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAE/B,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAe;QACzB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,sBAAsB,CACpD,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,EACjC,OAAO,CACV,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3B,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,gBAAgB,CAClB,OAAiC,EACjC,OAAgB;QAEhB,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3E,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,OAAe;QACrC,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC9D,CAAC;IAED,KAAK,CAAC,mBAAmB;QACrB,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,mBAAmB,EAAE,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,KAAK;QACP,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACjC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACzB,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;CACJ"}
|
package/esm/utils/index.d.ts
CHANGED
package/esm/utils/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC3D,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC3D,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC"}
|
package/esm/utils/index.js
CHANGED
package/esm/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC3D,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC3D,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An object to keep current Node.js process alive even when no code is running.
|
|
3
|
+
*
|
|
4
|
+
* Does nothing in Web environments.
|
|
5
|
+
*
|
|
6
|
+
* Note that it does't have reference counting. Calling `unref` will
|
|
7
|
+
* remove the ref no matter how many times `ref` has been previously called, and vice versa.
|
|
8
|
+
* This is the same as how Node.js works.
|
|
9
|
+
*/
|
|
10
|
+
export declare class Ref {
|
|
11
|
+
#private;
|
|
12
|
+
constructor(options?: {
|
|
13
|
+
unref?: boolean | undefined;
|
|
14
|
+
});
|
|
15
|
+
ref(): void;
|
|
16
|
+
unref(): void;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=ref.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ref.d.ts","sourceRoot":"","sources":["../../src/utils/ref.ts"],"names":[],"mappings":"AAOA;;;;;;;;GAQG;AACH,qBAAa,GAAG;;gBAGA,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;KAAE;IAMrD,GAAG;IAKH,KAAK;CAMR"}
|
package/esm/utils/ref.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const { setInterval, clearInterval } = globalThis;
|
|
2
|
+
/**
|
|
3
|
+
* An object to keep current Node.js process alive even when no code is running.
|
|
4
|
+
*
|
|
5
|
+
* Does nothing in Web environments.
|
|
6
|
+
*
|
|
7
|
+
* Note that it does't have reference counting. Calling `unref` will
|
|
8
|
+
* remove the ref no matter how many times `ref` has been previously called, and vice versa.
|
|
9
|
+
* This is the same as how Node.js works.
|
|
10
|
+
*/
|
|
11
|
+
export class Ref {
|
|
12
|
+
#intervalId;
|
|
13
|
+
constructor(options) {
|
|
14
|
+
if (!options?.unref) {
|
|
15
|
+
this.ref();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
ref() {
|
|
19
|
+
// `setInterval` can keep current Node.js alive, the delay value doesn't matter
|
|
20
|
+
this.#intervalId = setInterval(() => { }, 60 * 1000);
|
|
21
|
+
}
|
|
22
|
+
unref() {
|
|
23
|
+
if (this.#intervalId) {
|
|
24
|
+
clearInterval(this.#intervalId);
|
|
25
|
+
this.#intervalId = undefined;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=ref.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ref.js","sourceRoot":"","sources":["../../src/utils/ref.ts"],"names":[],"mappings":"AAKA,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,GAAG,UAAwC,CAAC;AAEhF;;;;;;;;GAQG;AACH,MAAM,OAAO,GAAG;IACZ,WAAW,CAAqB;IAEhC,YAAY,OAAyC;QACjD,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;YAClB,IAAI,CAAC,GAAG,EAAE,CAAC;QACf,CAAC;IACL,CAAC;IAED,GAAG;QACC,+EAA+E;QAC/E,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE,GAAE,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IACxD,CAAC;IAED,KAAK;QACD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACnB,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAChC,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QACjC,CAAC;IACL,CAAC;CACJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yume-chan/adb",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "TypeScript implementation of Android Debug Bridge (ADB) protocol.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adb",
|
|
@@ -28,17 +28,17 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@yume-chan/async": "^4.0.2",
|
|
30
30
|
"@yume-chan/event": "^1.0.0",
|
|
31
|
+
"@yume-chan/no-data-view": "^1.0.0",
|
|
31
32
|
"@yume-chan/stream-extra": "^1.0.0",
|
|
32
|
-
"@yume-chan/struct": "^1.0.0"
|
|
33
|
-
"@yume-chan/no-data-view": "^1.0.0"
|
|
33
|
+
"@yume-chan/struct": "^1.0.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@types/node": "^22.10.
|
|
37
|
-
"prettier": "^3.4.
|
|
36
|
+
"@types/node": "^22.10.2",
|
|
37
|
+
"prettier": "^3.4.2",
|
|
38
38
|
"typescript": "^5.7.2",
|
|
39
39
|
"@yume-chan/eslint-config": "^1.0.0",
|
|
40
|
-
"@yume-chan/
|
|
41
|
-
"@yume-chan/
|
|
40
|
+
"@yume-chan/tsconfig": "^1.0.0",
|
|
41
|
+
"@yume-chan/test-runner": "^1.0.0"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "tsc -b tsconfig.build.json",
|
package/src/server/client.ts
CHANGED
|
@@ -3,123 +3,28 @@
|
|
|
3
3
|
import type { MaybePromiseLike } from "@yume-chan/async";
|
|
4
4
|
import { PromiseResolver } from "@yume-chan/async";
|
|
5
5
|
import type { Event } from "@yume-chan/event";
|
|
6
|
-
import { EventEmitter } from "@yume-chan/event";
|
|
7
6
|
import { getUint64LittleEndian } from "@yume-chan/no-data-view";
|
|
8
7
|
import type {
|
|
9
8
|
AbortSignal,
|
|
10
9
|
MaybeConsumable,
|
|
11
10
|
ReadableWritablePair,
|
|
12
|
-
WritableStreamDefaultWriter,
|
|
13
11
|
} from "@yume-chan/stream-extra";
|
|
14
|
-
import {
|
|
15
|
-
BufferedReadableStream,
|
|
16
|
-
tryCancel,
|
|
17
|
-
tryClose,
|
|
18
|
-
} from "@yume-chan/stream-extra";
|
|
19
|
-
import {
|
|
20
|
-
bipedal,
|
|
21
|
-
decodeUtf8,
|
|
22
|
-
encodeUtf8,
|
|
23
|
-
TextDecoder,
|
|
24
|
-
} from "@yume-chan/struct";
|
|
12
|
+
import { AbortController } from "@yume-chan/stream-extra";
|
|
25
13
|
|
|
26
14
|
import type { AdbIncomingSocketHandler, AdbSocket, Closeable } from "../adb.js";
|
|
27
15
|
import { AdbBanner } from "../banner.js";
|
|
28
16
|
import type { DeviceObserver as DeviceObserverBase } from "../device-observer.js";
|
|
29
17
|
import type { AdbFeature } from "../features.js";
|
|
30
|
-
import { hexToNumber, sequenceEqual
|
|
18
|
+
import { hexToNumber, sequenceEqual } from "../utils/index.js";
|
|
31
19
|
|
|
20
|
+
import { AdbServerDeviceObserverOwner } from "./observer.js";
|
|
21
|
+
import { AdbServerStream, FAIL } from "./stream.js";
|
|
32
22
|
import { AdbServerTransport } from "./transport.js";
|
|
33
23
|
|
|
34
|
-
const OKAY = encodeUtf8("OKAY");
|
|
35
|
-
const FAIL = encodeUtf8("FAIL");
|
|
36
|
-
|
|
37
|
-
class AdbServerStream {
|
|
38
|
-
#connection: AdbServerClient.ServerConnection;
|
|
39
|
-
#buffered: BufferedReadableStream;
|
|
40
|
-
#writer: WritableStreamDefaultWriter<Uint8Array>;
|
|
41
|
-
|
|
42
|
-
constructor(connection: AdbServerClient.ServerConnection) {
|
|
43
|
-
this.#connection = connection;
|
|
44
|
-
this.#buffered = new BufferedReadableStream(connection.readable);
|
|
45
|
-
this.#writer = connection.writable.getWriter();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
readExactly(length: number): MaybePromiseLike<Uint8Array> {
|
|
49
|
-
return this.#buffered.readExactly(length);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
readString = bipedal(function* (this: AdbServerStream, then) {
|
|
53
|
-
const data = yield* then(this.readExactly(4));
|
|
54
|
-
const length = hexToNumber(data);
|
|
55
|
-
if (length === 0) {
|
|
56
|
-
return "";
|
|
57
|
-
} else {
|
|
58
|
-
const decoder = new TextDecoder();
|
|
59
|
-
let result = "";
|
|
60
|
-
const iterator = this.#buffered.iterateExactly(length);
|
|
61
|
-
while (true) {
|
|
62
|
-
const { done, value } = iterator.next();
|
|
63
|
-
if (done) {
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
|
-
result += decoder.decode(yield* then(value), { stream: true });
|
|
67
|
-
}
|
|
68
|
-
result += decoder.decode();
|
|
69
|
-
return result;
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
async writeString(value: string): Promise<void> {
|
|
74
|
-
// TODO: investigate using `encodeUtf8("0000" + value)` then modifying the length
|
|
75
|
-
// That way allocates a new string (hopefully only a rope) instead of a new buffer
|
|
76
|
-
const encoded = encodeUtf8(value);
|
|
77
|
-
const buffer = new Uint8Array(4 + encoded.length);
|
|
78
|
-
write4HexDigits(buffer, 0, encoded.length);
|
|
79
|
-
buffer.set(encoded, 4);
|
|
80
|
-
await this.#writer.write(buffer);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async readOkay(): Promise<void> {
|
|
84
|
-
const response = await this.readExactly(4);
|
|
85
|
-
if (sequenceEqual(response, OKAY)) {
|
|
86
|
-
// `OKAY` is followed by data length and data
|
|
87
|
-
// But different services want to parse the data differently
|
|
88
|
-
// So don't read the data here
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (sequenceEqual(response, FAIL)) {
|
|
93
|
-
const reason = await this.readString();
|
|
94
|
-
throw new Error(reason);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
throw new Error(`Unexpected response: ${decodeUtf8(response)}`);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
release() {
|
|
101
|
-
this.#writer.releaseLock();
|
|
102
|
-
return {
|
|
103
|
-
readable: this.#buffered.release(),
|
|
104
|
-
writable: this.#connection.writable,
|
|
105
|
-
closed: this.#connection.closed,
|
|
106
|
-
close: () => this.#connection.close(),
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async dispose() {
|
|
111
|
-
void tryCancel(this.#buffered);
|
|
112
|
-
void tryClose(this.#writer);
|
|
113
|
-
await this.#connection.close();
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
24
|
/**
|
|
118
25
|
* Client for the ADB Server.
|
|
119
26
|
*/
|
|
120
27
|
export class AdbServerClient {
|
|
121
|
-
static readonly VERSION = 41;
|
|
122
|
-
|
|
123
28
|
static parseDeviceList(value: string): AdbServerClient.Device[] {
|
|
124
29
|
const devices: AdbServerClient.Device[] = [];
|
|
125
30
|
for (const line of value.split("\n")) {
|
|
@@ -196,6 +101,7 @@ export class AdbServerClient {
|
|
|
196
101
|
|
|
197
102
|
readonly wireless = new AdbServerClient.WirelessCommands(this);
|
|
198
103
|
readonly mDns = new AdbServerClient.MDnsCommands(this);
|
|
104
|
+
#observerOwner = new AdbServerDeviceObserverOwner(this);
|
|
199
105
|
|
|
200
106
|
constructor(connector: AdbServerClient.ServerConnector) {
|
|
201
107
|
this.connector = connector;
|
|
@@ -240,11 +146,11 @@ export class AdbServerClient {
|
|
|
240
146
|
}
|
|
241
147
|
}
|
|
242
148
|
|
|
243
|
-
async validateVersion() {
|
|
149
|
+
async validateVersion(minimalVersion: number) {
|
|
244
150
|
const version = await this.getVersion();
|
|
245
|
-
if (version
|
|
151
|
+
if (version < minimalVersion) {
|
|
246
152
|
throw new Error(
|
|
247
|
-
`adb server version (${version}) doesn't match this client (${
|
|
153
|
+
`adb server version (${version}) doesn't match this client (${minimalVersion})`,
|
|
248
154
|
);
|
|
249
155
|
}
|
|
250
156
|
}
|
|
@@ -288,61 +194,10 @@ export class AdbServerClient {
|
|
|
288
194
|
/**
|
|
289
195
|
* Monitors device list changes.
|
|
290
196
|
*/
|
|
291
|
-
async trackDevices(
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
const onError = new EventEmitter<Error>();
|
|
296
|
-
const onDeviceAdd = new EventEmitter<AdbServerClient.Device[]>();
|
|
297
|
-
const onDeviceRemove = new EventEmitter<AdbServerClient.Device[]>();
|
|
298
|
-
const onListChange = new EventEmitter<AdbServerClient.Device[]>();
|
|
299
|
-
|
|
300
|
-
void (async () => {
|
|
301
|
-
try {
|
|
302
|
-
while (true) {
|
|
303
|
-
const response = await connection.readString();
|
|
304
|
-
const next = AdbServerClient.parseDeviceList(response);
|
|
305
|
-
|
|
306
|
-
const added: AdbServerClient.Device[] = [];
|
|
307
|
-
for (const nextDevice of next) {
|
|
308
|
-
const index = current.findIndex(
|
|
309
|
-
(device) =>
|
|
310
|
-
device.transportId === nextDevice.transportId,
|
|
311
|
-
);
|
|
312
|
-
if (index === -1) {
|
|
313
|
-
added.push(nextDevice);
|
|
314
|
-
continue;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
current[index] = current[current.length - 1]!;
|
|
318
|
-
current.length -= 1;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
if (added.length) {
|
|
322
|
-
onDeviceAdd.fire(added);
|
|
323
|
-
}
|
|
324
|
-
if (current.length) {
|
|
325
|
-
onDeviceRemove.fire(current);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
current = next;
|
|
329
|
-
onListChange.fire(current);
|
|
330
|
-
}
|
|
331
|
-
} catch (e) {
|
|
332
|
-
onError.fire(e as Error);
|
|
333
|
-
}
|
|
334
|
-
})();
|
|
335
|
-
|
|
336
|
-
return {
|
|
337
|
-
onError: onError.event,
|
|
338
|
-
onDeviceAdd: onDeviceAdd.event,
|
|
339
|
-
onDeviceRemove: onDeviceRemove.event,
|
|
340
|
-
onListChange: onListChange.event,
|
|
341
|
-
get current() {
|
|
342
|
-
return current;
|
|
343
|
-
},
|
|
344
|
-
stop: () => connection.dispose(),
|
|
345
|
-
};
|
|
197
|
+
async trackDevices(
|
|
198
|
+
options?: AdbServerClient.ServerConnectionOptions,
|
|
199
|
+
): Promise<AdbServerClient.DeviceObserver> {
|
|
200
|
+
return this.#observerOwner.createObserver(options);
|
|
346
201
|
}
|
|
347
202
|
|
|
348
203
|
/**
|
|
@@ -412,20 +267,22 @@ export class AdbServerClient {
|
|
|
412
267
|
device: AdbServerClient.DeviceSelector,
|
|
413
268
|
service: string,
|
|
414
269
|
): Promise<AdbServerClient.Socket> {
|
|
415
|
-
await this.validateVersion();
|
|
416
|
-
|
|
417
270
|
let switchService: string;
|
|
418
271
|
let transportId: bigint | undefined;
|
|
419
272
|
if (!device) {
|
|
273
|
+
await this.validateVersion(41);
|
|
420
274
|
switchService = `host:tport:any`;
|
|
421
275
|
} else if ("transportId" in device) {
|
|
422
276
|
switchService = `host:transport-id:${device.transportId}`;
|
|
423
277
|
transportId = device.transportId;
|
|
424
278
|
} else if ("serial" in device) {
|
|
279
|
+
await this.validateVersion(41);
|
|
425
280
|
switchService = `host:tport:serial:${device.serial}`;
|
|
426
281
|
} else if ("usb" in device) {
|
|
282
|
+
await this.validateVersion(41);
|
|
427
283
|
switchService = `host:tport:usb`;
|
|
428
284
|
} else if ("tcp" in device) {
|
|
285
|
+
await this.validateVersion(41);
|
|
429
286
|
switchService = `host:tport:local`;
|
|
430
287
|
} else {
|
|
431
288
|
throw new TypeError("Invalid device selector");
|
|
@@ -467,18 +324,7 @@ export class AdbServerClient {
|
|
|
467
324
|
throw e;
|
|
468
325
|
}
|
|
469
326
|
}
|
|
470
|
-
|
|
471
|
-
/**
|
|
472
|
-
* Wait for a device to be connected or disconnected.
|
|
473
|
-
*
|
|
474
|
-
* `adb wait-for-<state>`
|
|
475
|
-
*
|
|
476
|
-
* @param device The device selector
|
|
477
|
-
* @param state The state to wait for
|
|
478
|
-
* @param options The options
|
|
479
|
-
* @returns A promise that resolves when the condition is met.
|
|
480
|
-
*/
|
|
481
|
-
async waitFor(
|
|
327
|
+
async #waitForUnchecked(
|
|
482
328
|
device: AdbServerClient.DeviceSelector,
|
|
483
329
|
state: "device" | "disconnect",
|
|
484
330
|
options?: AdbServerClient.ServerConnectionOptions,
|
|
@@ -513,6 +359,60 @@ export class AdbServerClient {
|
|
|
513
359
|
}
|
|
514
360
|
}
|
|
515
361
|
|
|
362
|
+
/**
|
|
363
|
+
* Wait for a device to be connected or disconnected.
|
|
364
|
+
*
|
|
365
|
+
* `adb wait-for-<state>`
|
|
366
|
+
*
|
|
367
|
+
* @param device The device selector
|
|
368
|
+
* @param state The state to wait for
|
|
369
|
+
* @param options The options
|
|
370
|
+
* @returns A promise that resolves when the condition is met.
|
|
371
|
+
*/
|
|
372
|
+
async waitFor(
|
|
373
|
+
device: AdbServerClient.DeviceSelector,
|
|
374
|
+
state: "device" | "disconnect",
|
|
375
|
+
options?: AdbServerClient.ServerConnectionOptions,
|
|
376
|
+
): Promise<void> {
|
|
377
|
+
if (state === "disconnect") {
|
|
378
|
+
await this.validateVersion(41);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return this.#waitForUnchecked(device, state, options);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
async waitForDisconnect(
|
|
385
|
+
transportId: bigint,
|
|
386
|
+
options?: AdbServerClient.ServerConnectionOptions,
|
|
387
|
+
): Promise<void> {
|
|
388
|
+
const serverVersion = await this.getVersion();
|
|
389
|
+
if (serverVersion >= 41) {
|
|
390
|
+
return this.#waitForUnchecked(
|
|
391
|
+
{ transportId },
|
|
392
|
+
"disconnect",
|
|
393
|
+
options,
|
|
394
|
+
);
|
|
395
|
+
} else {
|
|
396
|
+
const observer = await this.trackDevices(options);
|
|
397
|
+
return new Promise<void>((resolve, reject) => {
|
|
398
|
+
observer.onDeviceRemove((devices) => {
|
|
399
|
+
if (
|
|
400
|
+
devices.some(
|
|
401
|
+
(device) => device.transportId === transportId,
|
|
402
|
+
)
|
|
403
|
+
) {
|
|
404
|
+
observer.stop();
|
|
405
|
+
resolve();
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
observer.onError((e) => {
|
|
409
|
+
observer.stop();
|
|
410
|
+
reject(e);
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
516
416
|
/**
|
|
517
417
|
* Creates an ADB Transport for the specified device.
|
|
518
418
|
*/
|
|
@@ -533,12 +433,26 @@ export class AdbServerClient {
|
|
|
533
433
|
features,
|
|
534
434
|
);
|
|
535
435
|
|
|
536
|
-
|
|
436
|
+
const waitAbortController = new AbortController();
|
|
437
|
+
const disconnected = this.waitForDisconnect(transportId, {
|
|
438
|
+
unref: true,
|
|
439
|
+
signal: waitAbortController.signal,
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
const transport = new AdbServerTransport(
|
|
537
443
|
this,
|
|
538
444
|
info?.serial ?? "",
|
|
539
445
|
banner,
|
|
540
446
|
transportId,
|
|
447
|
+
disconnected,
|
|
541
448
|
);
|
|
449
|
+
|
|
450
|
+
transport.disconnected.then(
|
|
451
|
+
() => waitAbortController.abort(),
|
|
452
|
+
() => waitAbortController.abort(),
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
return transport;
|
|
542
456
|
}
|
|
543
457
|
}
|
|
544
458
|
|
package/src/server/index.ts
CHANGED