@yume-chan/adb 0.0.19 → 0.0.21

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.
Files changed (197) hide show
  1. package/CHANGELOG.json +57 -0
  2. package/CHANGELOG.md +26 -1
  3. package/README.md +222 -103
  4. package/esm/adb.d.ts +28 -45
  5. package/esm/adb.d.ts.map +1 -1
  6. package/esm/adb.js +34 -213
  7. package/esm/adb.js.map +1 -1
  8. package/esm/banner.d.ts +17 -0
  9. package/esm/banner.d.ts.map +1 -0
  10. package/esm/banner.js +67 -0
  11. package/esm/banner.js.map +1 -0
  12. package/esm/commands/base.d.ts.map +1 -1
  13. package/esm/commands/base.js.map +1 -1
  14. package/esm/commands/framebuffer.d.ts +9 -0
  15. package/esm/commands/framebuffer.d.ts.map +1 -1
  16. package/esm/commands/framebuffer.js +27 -3
  17. package/esm/commands/framebuffer.js.map +1 -1
  18. package/esm/commands/power.d.ts +1 -1
  19. package/esm/commands/power.d.ts.map +1 -1
  20. package/esm/commands/power.js +2 -2
  21. package/esm/commands/power.js.map +1 -1
  22. package/esm/commands/reverse.d.ts +17 -18
  23. package/esm/commands/reverse.d.ts.map +1 -1
  24. package/esm/commands/reverse.js +53 -48
  25. package/esm/commands/reverse.js.map +1 -1
  26. package/esm/commands/subprocess/command.d.ts +1 -1
  27. package/esm/commands/subprocess/command.d.ts.map +1 -1
  28. package/esm/commands/subprocess/command.js +15 -13
  29. package/esm/commands/subprocess/command.js.map +1 -1
  30. package/esm/commands/subprocess/protocols/none.d.ts +3 -8
  31. package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
  32. package/esm/commands/subprocess/protocols/none.js +16 -16
  33. package/esm/commands/subprocess/protocols/none.js.map +1 -1
  34. package/esm/commands/subprocess/protocols/shell.d.ts +3 -9
  35. package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
  36. package/esm/commands/subprocess/protocols/shell.js +63 -57
  37. package/esm/commands/subprocess/protocols/shell.js.map +1 -1
  38. package/esm/commands/subprocess/protocols/types.d.ts +1 -2
  39. package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
  40. package/esm/commands/sync/list.js +2 -2
  41. package/esm/commands/sync/push.d.ts +14 -3
  42. package/esm/commands/sync/push.d.ts.map +1 -1
  43. package/esm/commands/sync/push.js +9 -9
  44. package/esm/commands/sync/push.js.map +1 -1
  45. package/esm/commands/sync/request.js +2 -2
  46. package/esm/commands/sync/request.js.map +1 -1
  47. package/esm/commands/sync/response.d.ts +5 -3
  48. package/esm/commands/sync/response.d.ts.map +1 -1
  49. package/esm/commands/sync/response.js +7 -5
  50. package/esm/commands/sync/response.js.map +1 -1
  51. package/esm/commands/sync/socket.d.ts +8 -14
  52. package/esm/commands/sync/socket.d.ts.map +1 -1
  53. package/esm/commands/sync/socket.js +35 -32
  54. package/esm/commands/sync/socket.js.map +1 -1
  55. package/esm/commands/sync/stat.js +4 -4
  56. package/esm/commands/sync/stat.js.map +1 -1
  57. package/esm/commands/sync/sync.d.ts +26 -18
  58. package/esm/commands/sync/sync.d.ts.map +1 -1
  59. package/esm/commands/sync/sync.js +36 -25
  60. package/esm/commands/sync/sync.js.map +1 -1
  61. package/esm/commands/tcpip.d.ts +2 -2
  62. package/esm/commands/tcpip.d.ts.map +1 -1
  63. package/esm/commands/tcpip.js +4 -2
  64. package/esm/commands/tcpip.js.map +1 -1
  65. package/esm/{auth.d.ts → daemon/auth.d.ts} +12 -11
  66. package/esm/daemon/auth.d.ts.map +1 -0
  67. package/esm/{auth.js → daemon/auth.js} +31 -22
  68. package/esm/daemon/auth.js.map +1 -0
  69. package/esm/{crypto.d.ts → daemon/crypto.d.ts} +5 -5
  70. package/esm/daemon/crypto.d.ts.map +1 -0
  71. package/esm/{crypto.js → daemon/crypto.js} +24 -28
  72. package/esm/daemon/crypto.js.map +1 -0
  73. package/esm/{backend.d.ts → daemon/device.d.ts} +2 -2
  74. package/esm/daemon/device.d.ts.map +1 -0
  75. package/esm/daemon/device.js +2 -0
  76. package/esm/daemon/device.js.map +1 -0
  77. package/esm/{socket → daemon}/dispatcher.d.ts +12 -30
  78. package/esm/daemon/dispatcher.d.ts.map +1 -0
  79. package/esm/{socket → daemon}/dispatcher.js +80 -78
  80. package/esm/daemon/dispatcher.js.map +1 -0
  81. package/esm/daemon/index.d.ts +8 -0
  82. package/esm/daemon/index.d.ts.map +1 -0
  83. package/esm/daemon/index.js +8 -0
  84. package/esm/daemon/index.js.map +1 -0
  85. package/esm/{packet.d.ts → daemon/packet.d.ts} +4 -4
  86. package/esm/daemon/packet.d.ts.map +1 -0
  87. package/esm/{packet.js → daemon/packet.js} +2 -2
  88. package/esm/{packet.js.map → daemon/packet.js.map} +1 -1
  89. package/esm/{socket → daemon}/socket.d.ts +15 -19
  90. package/esm/daemon/socket.d.ts.map +1 -0
  91. package/esm/{socket → daemon}/socket.js +49 -42
  92. package/esm/daemon/socket.js.map +1 -0
  93. package/esm/daemon/transport.d.ts +53 -0
  94. package/esm/daemon/transport.d.ts.map +1 -0
  95. package/esm/daemon/transport.js +186 -0
  96. package/esm/daemon/transport.js.map +1 -0
  97. package/esm/features.js +1 -1
  98. package/esm/features.js.map +1 -1
  99. package/esm/index.d.ts +3 -5
  100. package/esm/index.d.ts.map +1 -1
  101. package/esm/index.js +3 -5
  102. package/esm/index.js.map +1 -1
  103. package/esm/server/client.d.ts +78 -0
  104. package/esm/server/client.d.ts.map +1 -0
  105. package/esm/server/client.js +328 -0
  106. package/esm/server/client.js.map +1 -0
  107. package/esm/server/index.d.ts +3 -0
  108. package/esm/server/index.d.ts.map +1 -0
  109. package/esm/server/index.js +3 -0
  110. package/esm/server/index.js.map +1 -0
  111. package/esm/server/transport.d.ts +19 -0
  112. package/esm/server/transport.d.ts.map +1 -0
  113. package/esm/server/transport.js +44 -0
  114. package/esm/server/transport.js.map +1 -0
  115. package/esm/utils/auto-reset-event.d.ts +1 -2
  116. package/esm/utils/auto-reset-event.d.ts.map +1 -1
  117. package/esm/utils/auto-reset-event.js +12 -12
  118. package/esm/utils/auto-reset-event.js.map +1 -1
  119. package/esm/utils/base64.js +5 -5
  120. package/esm/utils/base64.js.map +1 -1
  121. package/esm/utils/conditional-variable.d.ts +1 -2
  122. package/esm/utils/conditional-variable.d.ts.map +1 -1
  123. package/esm/utils/conditional-variable.js +10 -10
  124. package/esm/utils/conditional-variable.js.map +1 -1
  125. package/esm/utils/hex.d.ts +3 -0
  126. package/esm/utils/hex.d.ts.map +1 -0
  127. package/esm/utils/hex.js +55 -0
  128. package/esm/utils/hex.js.map +1 -0
  129. package/esm/utils/index.d.ts +2 -0
  130. package/esm/utils/index.d.ts.map +1 -1
  131. package/esm/utils/index.js +2 -0
  132. package/esm/utils/index.js.map +1 -1
  133. package/esm/utils/no-op.d.ts +7 -0
  134. package/esm/utils/no-op.d.ts.map +1 -0
  135. package/esm/utils/no-op.js +12 -0
  136. package/esm/utils/no-op.js.map +1 -0
  137. package/package.json +12 -12
  138. package/src/adb.ts +75 -274
  139. package/src/banner.ts +82 -0
  140. package/src/commands/base.ts +1 -1
  141. package/src/commands/framebuffer.ts +31 -3
  142. package/src/commands/power.ts +10 -10
  143. package/src/commands/reverse.ts +77 -82
  144. package/src/commands/subprocess/command.ts +24 -25
  145. package/src/commands/subprocess/protocols/none.ts +29 -30
  146. package/src/commands/subprocess/protocols/shell.ts +87 -89
  147. package/src/commands/subprocess/protocols/types.ts +1 -2
  148. package/src/commands/sync/list.ts +7 -7
  149. package/src/commands/sync/pull.ts +4 -4
  150. package/src/commands/sync/push.ts +28 -16
  151. package/src/commands/sync/request.ts +4 -4
  152. package/src/commands/sync/response.ts +13 -11
  153. package/src/commands/sync/socket.ts +48 -46
  154. package/src/commands/sync/stat.ts +5 -5
  155. package/src/commands/sync/sync.ts +55 -43
  156. package/src/commands/tcpip.ts +6 -4
  157. package/src/{auth.ts → daemon/auth.ts} +62 -43
  158. package/src/{crypto.ts → daemon/crypto.ts} +33 -41
  159. package/src/{backend.ts → daemon/device.ts} +1 -1
  160. package/src/{socket → daemon}/dispatcher.ts +103 -109
  161. package/src/daemon/index.ts +7 -0
  162. package/src/{packet.ts → daemon/packet.ts} +6 -6
  163. package/src/{socket → daemon}/socket.ts +77 -67
  164. package/src/daemon/transport.ts +281 -0
  165. package/src/index.ts +3 -5
  166. package/src/server/client.ts +473 -0
  167. package/src/server/index.ts +2 -0
  168. package/src/server/transport.ts +77 -0
  169. package/src/utils/auto-reset-event.ts +16 -16
  170. package/src/utils/base64.ts +5 -5
  171. package/src/utils/conditional-variable.ts +14 -14
  172. package/src/utils/hex.ts +58 -0
  173. package/src/utils/index.ts +2 -0
  174. package/src/utils/no-op.ts +12 -0
  175. package/tsconfig.build.json +12 -1
  176. package/tsconfig.build.tsbuildinfo +1 -1
  177. package/esm/auth.d.ts.map +0 -1
  178. package/esm/auth.js.map +0 -1
  179. package/esm/backend.d.ts.map +0 -1
  180. package/esm/backend.js +0 -2
  181. package/esm/backend.js.map +0 -1
  182. package/esm/commands/install.d.ts +0 -10
  183. package/esm/commands/install.d.ts.map +0 -1
  184. package/esm/commands/install.js +0 -29
  185. package/esm/commands/install.js.map +0 -1
  186. package/esm/crypto.d.ts.map +0 -1
  187. package/esm/crypto.js.map +0 -1
  188. package/esm/packet.d.ts.map +0 -1
  189. package/esm/socket/dispatcher.d.ts.map +0 -1
  190. package/esm/socket/dispatcher.js.map +0 -1
  191. package/esm/socket/index.d.ts +0 -3
  192. package/esm/socket/index.d.ts.map +0 -1
  193. package/esm/socket/index.js +0 -3
  194. package/esm/socket/index.js.map +0 -1
  195. package/esm/socket/socket.d.ts.map +0 -1
  196. package/esm/socket/socket.js.map +0 -1
  197. package/src/socket/index.ts +0 -2
@@ -7,91 +7,93 @@ import {
7
7
  BufferedReadableStream,
8
8
  ConsumableWritableStream,
9
9
  } from "@yume-chan/stream-extra";
10
- import type { StructAsyncDeserializeStream } from "@yume-chan/struct";
10
+ import type { AsyncExactReadable } from "@yume-chan/struct";
11
11
 
12
- import type { AdbSocket } from "../../index.js";
13
- import { AutoResetEvent } from "../../index.js";
12
+ import type { AdbSocket } from "../../adb.js";
13
+ import { AutoResetEvent } from "../../utils/index.js";
14
14
 
15
- export class AdbSyncSocketLocked implements StructAsyncDeserializeStream {
16
- private readonly _writer: WritableStreamDefaultWriter<
17
- Consumable<Uint8Array>
18
- >;
19
- private readonly _readable: BufferedReadableStream;
20
- private readonly _socketLock: AutoResetEvent;
21
- private readonly _writeLock = new AutoResetEvent();
22
- private readonly _combiner: BufferCombiner;
15
+ export class AdbSyncSocketLocked implements AsyncExactReadable {
16
+ readonly #writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>;
17
+ readonly #readable: BufferedReadableStream;
18
+ readonly #socketLock: AutoResetEvent;
19
+ readonly #writeLock = new AutoResetEvent();
20
+ readonly #combiner: BufferCombiner;
23
21
 
24
- public constructor(
22
+ get position() {
23
+ return this.#readable.position;
24
+ }
25
+
26
+ constructor(
25
27
  writer: WritableStreamDefaultWriter<Consumable<Uint8Array>>,
26
28
  readable: BufferedReadableStream,
27
29
  bufferSize: number,
28
- lock: AutoResetEvent
30
+ lock: AutoResetEvent,
29
31
  ) {
30
- this._writer = writer;
31
- this._readable = readable;
32
- this._socketLock = lock;
33
- this._combiner = new BufferCombiner(bufferSize);
32
+ this.#writer = writer;
33
+ this.#readable = readable;
34
+ this.#socketLock = lock;
35
+ this.#combiner = new BufferCombiner(bufferSize);
34
36
  }
35
37
 
36
- private async writeInnerStream(buffer: Uint8Array) {
37
- await ConsumableWritableStream.write(this._writer, buffer);
38
+ async #writeInnerStream(buffer: Uint8Array) {
39
+ await ConsumableWritableStream.write(this.#writer, buffer);
38
40
  }
39
41
 
40
- public async flush() {
42
+ async flush() {
41
43
  try {
42
- await this._writeLock.wait();
43
- const buffer = this._combiner.flush();
44
+ await this.#writeLock.wait();
45
+ const buffer = this.#combiner.flush();
44
46
  if (buffer) {
45
- await this.writeInnerStream(buffer);
47
+ await this.#writeInnerStream(buffer);
46
48
  }
47
49
  } finally {
48
- this._writeLock.notifyOne();
50
+ this.#writeLock.notifyOne();
49
51
  }
50
52
  }
51
53
 
52
- public async write(data: Uint8Array) {
54
+ async write(data: Uint8Array) {
53
55
  try {
54
- await this._writeLock.wait();
55
- for (const buffer of this._combiner.push(data)) {
56
- await this.writeInnerStream(buffer);
56
+ await this.#writeLock.wait();
57
+ for (const buffer of this.#combiner.push(data)) {
58
+ await this.#writeInnerStream(buffer);
57
59
  }
58
60
  } finally {
59
- this._writeLock.notifyOne();
61
+ this.#writeLock.notifyOne();
60
62
  }
61
63
  }
62
64
 
63
- public async read(length: number) {
65
+ async readExactly(length: number) {
64
66
  await this.flush();
65
- return await this._readable.read(length);
67
+ return await this.#readable.readExactly(length);
66
68
  }
67
69
 
68
- public release(): void {
69
- this._combiner.flush();
70
- this._socketLock.notifyOne();
70
+ release(): void {
71
+ this.#combiner.flush();
72
+ this.#socketLock.notifyOne();
71
73
  }
72
74
  }
73
75
 
74
76
  export class AdbSyncSocket {
75
- private _lock = new AutoResetEvent();
76
- private _socket: AdbSocket;
77
- private _locked: AdbSyncSocketLocked;
77
+ readonly #lock = new AutoResetEvent();
78
+ readonly #socket: AdbSocket;
79
+ readonly #locked: AdbSyncSocketLocked;
78
80
 
79
- public constructor(socket: AdbSocket, bufferSize: number) {
80
- this._socket = socket;
81
- this._locked = new AdbSyncSocketLocked(
81
+ constructor(socket: AdbSocket, bufferSize: number) {
82
+ this.#socket = socket;
83
+ this.#locked = new AdbSyncSocketLocked(
82
84
  socket.writable.getWriter(),
83
85
  new BufferedReadableStream(socket.readable),
84
86
  bufferSize,
85
- this._lock
87
+ this.#lock,
86
88
  );
87
89
  }
88
90
 
89
- public async lock() {
90
- await this._lock.wait();
91
- return this._locked;
91
+ async lock() {
92
+ await this.#lock.wait();
93
+ return this.#locked;
92
94
  }
93
95
 
94
- public async close() {
95
- await this._socket.close();
96
+ async close() {
97
+ await this.#socket.close();
96
98
  }
97
99
  }
@@ -103,7 +103,7 @@ export type AdbSyncStatResponse =
103
103
  export async function adbSyncLstat(
104
104
  socket: AdbSyncSocket,
105
105
  path: string,
106
- v2: boolean
106
+ v2: boolean,
107
107
  ): Promise<AdbSyncStat> {
108
108
  const locked = await socket.lock();
109
109
  try {
@@ -112,14 +112,14 @@ export async function adbSyncLstat(
112
112
  return await adbSyncReadResponse(
113
113
  locked,
114
114
  AdbSyncResponseId.Lstat2,
115
- AdbSyncStatResponse
115
+ AdbSyncStatResponse,
116
116
  );
117
117
  } else {
118
118
  await adbSyncWriteRequest(locked, AdbSyncRequestId.Lstat, path);
119
119
  const response = await adbSyncReadResponse(
120
120
  locked,
121
121
  AdbSyncResponseId.Lstat,
122
- AdbSyncLstatResponse
122
+ AdbSyncLstatResponse,
123
123
  );
124
124
  return {
125
125
  mode: response.mode,
@@ -141,7 +141,7 @@ export async function adbSyncLstat(
141
141
 
142
142
  export async function adbSyncStat(
143
143
  socket: AdbSyncSocket,
144
- path: string
144
+ path: string,
145
145
  ): Promise<AdbSyncStatResponse> {
146
146
  const locked = await socket.lock();
147
147
  try {
@@ -149,7 +149,7 @@ export async function adbSyncStat(
149
149
  return await adbSyncReadResponse(
150
150
  locked,
151
151
  AdbSyncResponseId.Stat,
152
- AdbSyncStatResponse
152
+ AdbSyncStatResponse,
153
153
  );
154
154
  } finally {
155
155
  locked.release();
@@ -1,9 +1,8 @@
1
1
  import { AutoDisposable } from "@yume-chan/event";
2
2
  import type { Consumable, ReadableStream } from "@yume-chan/stream-extra";
3
3
 
4
- import type { Adb } from "../../adb.js";
4
+ import type { Adb, AdbSocket } from "../../adb.js";
5
5
  import { AdbFeature } from "../../features.js";
6
- import type { AdbSocket } from "../../socket/index.js";
7
6
  import { escapeArg } from "../subprocess/index.js";
8
7
 
9
8
  import type { AdbSyncEntry } from "./list.js";
@@ -11,6 +10,7 @@ import { adbSyncOpenDir } from "./list.js";
11
10
  import { adbSyncPull } from "./pull.js";
12
11
  import { adbSyncPush } from "./push.js";
13
12
  import { AdbSyncSocket } from "./socket.js";
13
+ import type { AdbSyncStat, LinuxFileType } from "./stat.js";
14
14
  import { adbSyncLstat, adbSyncStat } from "./stat.js";
15
15
 
16
16
  /**
@@ -32,7 +32,8 @@ export function dirname(path: string): string {
32
32
  export interface AdbSyncWriteOptions {
33
33
  filename: string;
34
34
  file: ReadableStream<Consumable<Uint8Array>>;
35
- mode?: number;
35
+ type?: LinuxFileType;
36
+ permission?: number;
36
37
  mtime?: number;
37
38
  dryRun?: boolean;
38
39
  }
@@ -41,63 +42,78 @@ export class AdbSync extends AutoDisposable {
41
42
  protected _adb: Adb;
42
43
  protected _socket: AdbSyncSocket;
43
44
 
44
- private _supportsStat: boolean;
45
- private _supportsListV2: boolean;
46
- private _fixedPushMkdir: boolean;
47
- private _supportsSendReceiveV2: boolean;
48
- private _needPushMkdirWorkaround: boolean;
45
+ readonly #supportsStat: boolean;
46
+ readonly #supportsListV2: boolean;
47
+ readonly #fixedPushMkdir: boolean;
48
+ readonly #supportsSendReceiveV2: boolean;
49
+ readonly #needPushMkdirWorkaround: boolean;
49
50
 
50
- public get supportsStat(): boolean {
51
- return this._supportsStat;
51
+ get supportsStat(): boolean {
52
+ return this.#supportsStat;
52
53
  }
53
54
 
54
- public get supportsListV2(): boolean {
55
- return this._supportsListV2;
55
+ get supportsListV2(): boolean {
56
+ return this.#supportsListV2;
56
57
  }
57
58
 
58
- public get fixedPushMkdir(): boolean {
59
- return this._fixedPushMkdir;
59
+ get fixedPushMkdir(): boolean {
60
+ return this.#fixedPushMkdir;
60
61
  }
61
62
 
62
- public get supportsSendReceiveV2(): boolean {
63
- return this._supportsSendReceiveV2;
63
+ get supportsSendReceiveV2(): boolean {
64
+ return this.#supportsSendReceiveV2;
64
65
  }
65
66
 
66
- public get needPushMkdirWorkaround(): boolean {
67
- return this._needPushMkdirWorkaround;
67
+ get needPushMkdirWorkaround(): boolean {
68
+ return this.#needPushMkdirWorkaround;
68
69
  }
69
70
 
70
- public constructor(adb: Adb, socket: AdbSocket) {
71
+ constructor(adb: Adb, socket: AdbSocket) {
71
72
  super();
72
73
 
73
74
  this._adb = adb;
74
75
  this._socket = new AdbSyncSocket(socket, adb.maxPayloadSize);
75
76
 
76
- this._supportsStat = adb.supportsFeature(AdbFeature.StatV2);
77
- this._supportsListV2 = adb.supportsFeature(AdbFeature.ListV2);
78
- this._fixedPushMkdir = adb.supportsFeature(AdbFeature.FixedPushMkdir);
79
- this._supportsSendReceiveV2 = adb.supportsFeature(
80
- AdbFeature.SendReceiveV2
77
+ this.#supportsStat = adb.supportsFeature(AdbFeature.StatV2);
78
+ this.#supportsListV2 = adb.supportsFeature(AdbFeature.ListV2);
79
+ this.#fixedPushMkdir = adb.supportsFeature(AdbFeature.FixedPushMkdir);
80
+ this.#supportsSendReceiveV2 = adb.supportsFeature(
81
+ AdbFeature.SendReceiveV2,
81
82
  );
82
83
  // https://android.googlesource.com/platform/packages/modules/adb/+/91768a57b7138166e0a3d11f79cd55909dda7014/client/file_sync_client.cpp#1361
83
- this._needPushMkdirWorkaround =
84
+ this.#needPushMkdirWorkaround =
84
85
  this._adb.supportsFeature(AdbFeature.ShellV2) &&
85
86
  !this.fixedPushMkdir;
86
87
  }
87
88
 
88
- public async lstat(path: string) {
89
- return await adbSyncLstat(this._socket, path, this.supportsStat);
89
+ /**
90
+ * Gets information of a file or folder.
91
+ *
92
+ * If `path` points to a symbolic link, the returned information is about the link itself (with `type` being `LinuxFileType.Link`).
93
+ */
94
+ async lstat(path: string): Promise<AdbSyncStat> {
95
+ return await adbSyncLstat(this._socket, path, this.#supportsStat);
90
96
  }
91
97
 
92
- public async stat(path: string) {
93
- if (!this.supportsStat) {
98
+ /**
99
+ * Gets the information of a file or folder.
100
+ *
101
+ * If `path` points to a symbolic link, it will be resolved and the returned information is about the target (with `type` being `LinuxFileType.File` or `LinuxFileType.Directory`).
102
+ */
103
+ async stat(path: string) {
104
+ if (!this.#supportsStat) {
94
105
  throw new Error("Not supported");
95
106
  }
96
107
 
97
108
  return await adbSyncStat(this._socket, path);
98
109
  }
99
110
 
100
- public async isDirectory(path: string): Promise<boolean> {
111
+ /**
112
+ * Checks if `path` is a directory, or a symbolic link to a directory.
113
+ *
114
+ * This uses `lstat` internally, thus works on all Android versions.
115
+ */
116
+ async isDirectory(path: string): Promise<boolean> {
101
117
  try {
102
118
  await this.lstat(path + "/");
103
119
  return true;
@@ -106,11 +122,11 @@ export class AdbSync extends AutoDisposable {
106
122
  }
107
123
  }
108
124
 
109
- public opendir(path: string): AsyncGenerator<AdbSyncEntry, void, void> {
125
+ opendir(path: string): AsyncGenerator<AdbSyncEntry, void, void> {
110
126
  return adbSyncOpenDir(this._socket, path, this.supportsListV2);
111
127
  }
112
128
 
113
- public async readdir(path: string) {
129
+ async readdir(path: string) {
114
130
  const results: AdbSyncEntry[] = [];
115
131
  for await (const entry of this.opendir(path)) {
116
132
  results.push(entry);
@@ -119,25 +135,21 @@ export class AdbSync extends AutoDisposable {
119
135
  }
120
136
 
121
137
  /**
122
- * Read the content of a file on device.
138
+ * Reads the content of a file on device.
123
139
  *
124
140
  * @param filename The full path of the file on device to read.
125
- * @returns A `ReadableStream` that reads from the file.
141
+ * @returns A `ReadableStream` that contains the file content.
126
142
  */
127
- public read(filename: string): ReadableStream<Uint8Array> {
143
+ read(filename: string): ReadableStream<Uint8Array> {
128
144
  return adbSyncPull(this._socket, filename);
129
145
  }
130
146
 
131
147
  /**
132
- * Write (or overwrite) a file on device.
148
+ * Writes a file on device. If the file name already exists, it will be overwritten.
133
149
  *
134
- * @param filename The full path of the file on device to write.
135
- * @param file The content to write.
136
- * @param mode The unix permissions of the file.
137
- * @param mtime The modified time of the file.
138
- * @returns A `WritableStream` that writes to the file.
150
+ * @param options The content and options of the file to write.
139
151
  */
140
- public async write(options: AdbSyncWriteOptions) {
152
+ async write(options: AdbSyncWriteOptions): Promise<void> {
141
153
  if (this.needPushMkdirWorkaround) {
142
154
  // It may fail if the path is already existed.
143
155
  // Ignore the result.
@@ -156,7 +168,7 @@ export class AdbSync extends AutoDisposable {
156
168
  });
157
169
  }
158
170
 
159
- public override async dispose() {
171
+ override async dispose() {
160
172
  super.dispose();
161
173
  await this._socket.close();
162
174
  }
@@ -1,21 +1,23 @@
1
1
  import { AdbCommandBase } from "./base.js";
2
2
 
3
3
  export class AdbTcpIpCommand extends AdbCommandBase {
4
- public async setPort(port: number): Promise<void> {
4
+ async setPort(port: number): Promise<string> {
5
5
  if (port <= 0) {
6
6
  throw new Error(`Invalid port ${port}`);
7
7
  }
8
8
 
9
9
  const output = await this.adb.createSocketAndWait(`tcpip:${port}`);
10
10
  if (output !== `restarting in TCP mode port: ${port}\n`) {
11
- throw new Error("Invalid response");
11
+ throw new Error(output);
12
12
  }
13
+ return output;
13
14
  }
14
15
 
15
- public async disable(): Promise<void> {
16
+ async disable(): Promise<string> {
16
17
  const output = await this.adb.createSocketAndWait("usb:");
17
18
  if (output !== "restarting in USB mode\n") {
18
- throw new Error("Invalid response");
19
+ throw new Error(output);
19
20
  }
21
+ return output;
20
22
  }
21
23
  }
@@ -1,28 +1,42 @@
1
1
  import { PromiseResolver } from "@yume-chan/async";
2
2
  import type { Disposable } from "@yume-chan/event";
3
3
  import type { ValueOrPromise } from "@yume-chan/struct";
4
+ import { EMPTY_UINT8_ARRAY } from "@yume-chan/struct";
4
5
 
5
6
  import {
6
- calculatePublicKey,
7
- calculatePublicKeyLength,
8
- sign,
7
+ calculateBase64EncodedLength,
8
+ encodeBase64,
9
+ encodeUtf8,
10
+ } from "../utils/index.js";
11
+
12
+ import {
13
+ adbGeneratePublicKey,
14
+ adbGetPublicKeySize,
15
+ rsaSign,
9
16
  } from "./crypto.js";
10
17
  import type { AdbPacketData } from "./packet.js";
11
18
  import { AdbCommand } from "./packet.js";
12
- import { calculateBase64EncodedLength, encodeBase64 } from "./utils/index.js";
13
19
 
14
- export type AdbKeyIterable = Iterable<Uint8Array> | AsyncIterable<Uint8Array>;
20
+ export interface AdbPrivateKey {
21
+ /**
22
+ * The private key in PKCS #8 format.
23
+ */
24
+ buffer: Uint8Array;
25
+ name?: string | undefined;
26
+ }
27
+
28
+ export type AdbKeyIterable =
29
+ | Iterable<AdbPrivateKey>
30
+ | AsyncIterable<AdbPrivateKey>;
15
31
 
16
32
  export interface AdbCredentialStore {
17
33
  /**
18
- * Generate and store a RSA private key with modulus length `2048` and public exponent `65537`.
19
- *
20
- * The returned `Uint8Array` is the private key in PKCS #8 format.
34
+ * Generates and stores a RSA private key with modulus length `2048` and public exponent `65537`.
21
35
  */
22
- generateKey(): ValueOrPromise<Uint8Array>;
36
+ generateKey(): ValueOrPromise<AdbPrivateKey>;
23
37
 
24
38
  /**
25
- * Synchronously or asynchronously iterate through all stored RSA private keys.
39
+ * Synchronously or asynchronously iterates through all stored RSA private keys.
26
40
  *
27
41
  * Each call to `iterateKeys` must return a different iterator that iterate through all stored keys.
28
42
  */
@@ -49,13 +63,13 @@ export interface AdbAuthenticator {
49
63
  */
50
64
  (
51
65
  credentialStore: AdbCredentialStore,
52
- getNextRequest: () => Promise<AdbPacketData>
66
+ getNextRequest: () => Promise<AdbPacketData>,
53
67
  ): AsyncIterable<AdbPacketData>;
54
68
  }
55
69
 
56
70
  export const AdbSignatureAuthenticator: AdbAuthenticator = async function* (
57
71
  credentialStore: AdbCredentialStore,
58
- getNextRequest: () => Promise<AdbPacketData>
72
+ getNextRequest: () => Promise<AdbPacketData>,
59
73
  ): AsyncIterable<AdbPacketData> {
60
74
  for await (const key of credentialStore.iterateKeys()) {
61
75
  const packet = await getNextRequest();
@@ -64,7 +78,7 @@ export const AdbSignatureAuthenticator: AdbAuthenticator = async function* (
64
78
  return;
65
79
  }
66
80
 
67
- const signature = sign(key, packet.payload);
81
+ const signature = rsaSign(key.buffer, packet.payload);
68
82
  yield {
69
83
  command: AdbCommand.Auth,
70
84
  arg0: AdbAuthType.Signature,
@@ -76,7 +90,7 @@ export const AdbSignatureAuthenticator: AdbAuthenticator = async function* (
76
90
 
77
91
  export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
78
92
  credentialStore: AdbCredentialStore,
79
- getNextRequest: () => Promise<AdbPacketData>
93
+ getNextRequest: () => Promise<AdbPacketData>,
80
94
  ): AsyncIterable<AdbPacketData> {
81
95
  const packet = await getNextRequest();
82
96
 
@@ -84,7 +98,7 @@ export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
84
98
  return;
85
99
  }
86
100
 
87
- let privateKey: Uint8Array | undefined;
101
+ let privateKey: AdbPrivateKey | undefined;
88
102
  for await (const key of credentialStore.iterateKeys()) {
89
103
  privateKey = key;
90
104
  break;
@@ -94,17 +108,27 @@ export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
94
108
  privateKey = await credentialStore.generateKey();
95
109
  }
96
110
 
97
- const publicKeyLength = calculatePublicKeyLength();
111
+ const publicKeyLength = adbGetPublicKeySize();
98
112
  const [publicKeyBase64Length] =
99
113
  calculateBase64EncodedLength(publicKeyLength);
100
114
 
115
+ const nameBuffer = privateKey.name?.length
116
+ ? encodeUtf8(privateKey.name)
117
+ : EMPTY_UINT8_ARRAY;
101
118
  const publicKeyBuffer = new Uint8Array(
102
- publicKeyBase64Length + 1 // Null character
119
+ publicKeyBase64Length +
120
+ (nameBuffer.length ? nameBuffer.length + 1 : 0) + // Space character + name
121
+ 1, // Null character
103
122
  );
104
123
 
105
- calculatePublicKey(privateKey, publicKeyBuffer);
124
+ adbGeneratePublicKey(privateKey.buffer, publicKeyBuffer);
106
125
  encodeBase64(publicKeyBuffer.subarray(0, publicKeyLength), publicKeyBuffer);
107
126
 
127
+ if (nameBuffer.length) {
128
+ publicKeyBuffer[publicKeyBase64Length] = 0x20;
129
+ publicKeyBuffer.set(nameBuffer, publicKeyBase64Length + 1);
130
+ }
131
+
108
132
  yield {
109
133
  command: AdbCommand.Auth,
110
134
  arg0: AdbAuthType.PublicKey,
@@ -119,39 +143,34 @@ export const ADB_DEFAULT_AUTHENTICATORS: AdbAuthenticator[] = [
119
143
  ];
120
144
 
121
145
  export class AdbAuthenticationProcessor implements Disposable {
122
- public readonly authenticators: readonly AdbAuthenticator[];
146
+ readonly authenticators: readonly AdbAuthenticator[];
123
147
 
124
- private readonly credentialStore: AdbCredentialStore;
148
+ readonly #credentialStore: AdbCredentialStore;
125
149
 
126
- private pendingRequest = new PromiseResolver<AdbPacketData>();
150
+ #pendingRequest = new PromiseResolver<AdbPacketData>();
151
+ #iterator: AsyncIterator<AdbPacketData, void, void> | undefined;
127
152
 
128
- private iterator: AsyncIterator<AdbPacketData, void, void> | undefined;
129
-
130
- public constructor(
153
+ constructor(
131
154
  authenticators: readonly AdbAuthenticator[],
132
- credentialStore: AdbCredentialStore
155
+ credentialStore: AdbCredentialStore,
133
156
  ) {
134
157
  this.authenticators = authenticators;
135
- this.credentialStore = credentialStore;
158
+ this.#credentialStore = credentialStore;
136
159
  }
137
160
 
138
- private getNextRequest = (): Promise<AdbPacketData> => {
139
- return this.pendingRequest.promise;
161
+ #getNextRequest = (): Promise<AdbPacketData> => {
162
+ return this.#pendingRequest.promise;
140
163
  };
141
164
 
142
- private async *invokeAuthenticator(): AsyncGenerator<
143
- AdbPacketData,
144
- void,
145
- void
146
- > {
165
+ async *#invokeAuthenticator(): AsyncGenerator<AdbPacketData, void, void> {
147
166
  for (const authenticator of this.authenticators) {
148
167
  for await (const packet of authenticator(
149
- this.credentialStore,
150
- this.getNextRequest
168
+ this.#credentialStore,
169
+ this.#getNextRequest,
151
170
  )) {
152
171
  // If the authenticator yielded a response
153
172
  // Prepare `nextRequest` for next authentication request
154
- this.pendingRequest = new PromiseResolver();
173
+ this.#pendingRequest = new PromiseResolver();
155
174
 
156
175
  // Yield the response to outer layer
157
176
  yield packet;
@@ -162,14 +181,14 @@ export class AdbAuthenticationProcessor implements Disposable {
162
181
  }
163
182
  }
164
183
 
165
- public async process(packet: AdbPacketData): Promise<AdbPacketData> {
166
- if (!this.iterator) {
167
- this.iterator = this.invokeAuthenticator();
184
+ async process(packet: AdbPacketData): Promise<AdbPacketData> {
185
+ if (!this.#iterator) {
186
+ this.#iterator = this.#invokeAuthenticator();
168
187
  }
169
188
 
170
- this.pendingRequest.resolve(packet);
189
+ this.#pendingRequest.resolve(packet);
171
190
 
172
- const result = await this.iterator.next();
191
+ const result = await this.#iterator.next();
173
192
  if (result.done) {
174
193
  throw new Error("No authenticator can handle the request");
175
194
  }
@@ -177,7 +196,7 @@ export class AdbAuthenticationProcessor implements Disposable {
177
196
  return result.value;
178
197
  }
179
198
 
180
- public dispose() {
181
- void this.iterator?.return?.();
199
+ dispose() {
200
+ void this.#iterator?.return?.();
182
201
  }
183
202
  }