@yume-chan/adb 0.0.16 → 0.0.18

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 (177) hide show
  1. package/CHANGELOG.json +18 -0
  2. package/CHANGELOG.md +13 -1
  3. package/LICENSE +1 -1
  4. package/esm/adb.d.ts +13 -8
  5. package/esm/adb.d.ts.map +1 -1
  6. package/esm/adb.js +63 -38
  7. package/esm/adb.js.map +1 -1
  8. package/esm/auth.d.ts +4 -4
  9. package/esm/auth.d.ts.map +1 -1
  10. package/esm/auth.js +6 -6
  11. package/esm/auth.js.map +1 -1
  12. package/esm/backend.d.ts +3 -3
  13. package/esm/backend.d.ts.map +1 -1
  14. package/esm/commands/base.d.ts +2 -2
  15. package/esm/commands/base.d.ts.map +1 -1
  16. package/esm/commands/base.js +1 -1
  17. package/esm/commands/base.js.map +1 -1
  18. package/esm/commands/framebuffer.d.ts +22 -6
  19. package/esm/commands/framebuffer.d.ts.map +1 -1
  20. package/esm/commands/framebuffer.js +33 -45
  21. package/esm/commands/framebuffer.js.map +1 -1
  22. package/esm/commands/install.d.ts +2 -2
  23. package/esm/commands/install.d.ts.map +1 -1
  24. package/esm/commands/install.js +12 -5
  25. package/esm/commands/install.js.map +1 -1
  26. package/esm/commands/power.d.ts.map +1 -1
  27. package/esm/commands/power.js +13 -9
  28. package/esm/commands/power.js.map +1 -1
  29. package/esm/commands/reverse.d.ts +5 -5
  30. package/esm/commands/reverse.d.ts.map +1 -1
  31. package/esm/commands/reverse.js +20 -18
  32. package/esm/commands/reverse.js.map +1 -1
  33. package/esm/commands/subprocess/command.d.ts +52 -0
  34. package/esm/commands/subprocess/command.d.ts.map +1 -0
  35. package/esm/commands/subprocess/command.js +81 -0
  36. package/esm/commands/subprocess/command.js.map +1 -0
  37. package/esm/commands/subprocess/index.d.ts +1 -53
  38. package/esm/commands/subprocess/index.d.ts.map +1 -1
  39. package/esm/commands/subprocess/index.js +1 -85
  40. package/esm/commands/subprocess/index.js.map +1 -1
  41. package/esm/commands/subprocess/protocols/none.d.ts +5 -5
  42. package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
  43. package/esm/commands/subprocess/protocols/none.js +5 -3
  44. package/esm/commands/subprocess/protocols/none.js.map +1 -1
  45. package/esm/commands/subprocess/protocols/shell.d.ts +4 -4
  46. package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
  47. package/esm/commands/subprocess/protocols/shell.js +28 -20
  48. package/esm/commands/subprocess/protocols/shell.js.map +1 -1
  49. package/esm/commands/subprocess/protocols/types.d.ts +7 -7
  50. package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
  51. package/esm/commands/sync/index.d.ts +1 -1
  52. package/esm/commands/sync/index.d.ts.map +1 -1
  53. package/esm/commands/sync/index.js +1 -1
  54. package/esm/commands/sync/index.js.map +1 -1
  55. package/esm/commands/sync/list.d.ts +7 -7
  56. package/esm/commands/sync/list.d.ts.map +1 -1
  57. package/esm/commands/sync/list.js +34 -50
  58. package/esm/commands/sync/list.js.map +1 -1
  59. package/esm/commands/sync/pull.d.ts +5 -4
  60. package/esm/commands/sync/pull.d.ts.map +1 -1
  61. package/esm/commands/sync/pull.js +21 -22
  62. package/esm/commands/sync/pull.js.map +1 -1
  63. package/esm/commands/sync/push.d.ts +4 -4
  64. package/esm/commands/sync/push.d.ts.map +1 -1
  65. package/esm/commands/sync/push.js +7 -11
  66. package/esm/commands/sync/push.js.map +1 -1
  67. package/esm/commands/sync/request.d.ts +4 -4
  68. package/esm/commands/sync/request.d.ts.map +1 -1
  69. package/esm/commands/sync/request.js +6 -6
  70. package/esm/commands/sync/request.js.map +1 -1
  71. package/esm/commands/sync/response.d.ts +5 -10
  72. package/esm/commands/sync/response.d.ts.map +1 -1
  73. package/esm/commands/sync/response.js +35 -26
  74. package/esm/commands/sync/response.js.map +1 -1
  75. package/esm/commands/sync/stat.d.ts +7 -7
  76. package/esm/commands/sync/stat.d.ts.map +1 -1
  77. package/esm/commands/sync/stat.js +48 -55
  78. package/esm/commands/sync/stat.js.map +1 -1
  79. package/esm/commands/sync/sync.d.ts +7 -7
  80. package/esm/commands/sync/sync.d.ts.map +1 -1
  81. package/esm/commands/sync/sync.js +25 -22
  82. package/esm/commands/sync/sync.js.map +1 -1
  83. package/esm/crypto.d.ts.map +1 -1
  84. package/esm/crypto.js +26 -16
  85. package/esm/crypto.js.map +1 -1
  86. package/esm/index.d.ts +9 -10
  87. package/esm/index.d.ts.map +1 -1
  88. package/esm/index.js +9 -10
  89. package/esm/index.js.map +1 -1
  90. package/esm/packet.d.ts +8 -8
  91. package/esm/packet.d.ts.map +1 -1
  92. package/esm/packet.js +14 -12
  93. package/esm/packet.js.map +1 -1
  94. package/esm/socket/dispatcher.d.ts +11 -6
  95. package/esm/socket/dispatcher.d.ts.map +1 -1
  96. package/esm/socket/dispatcher.js +28 -20
  97. package/esm/socket/dispatcher.js.map +1 -1
  98. package/esm/socket/index.d.ts +1 -1
  99. package/esm/socket/index.d.ts.map +1 -1
  100. package/esm/socket/index.js +1 -1
  101. package/esm/socket/index.js.map +1 -1
  102. package/esm/socket/socket.d.ts +5 -5
  103. package/esm/socket/socket.d.ts.map +1 -1
  104. package/esm/socket/socket.js +37 -17
  105. package/esm/socket/socket.js.map +1 -1
  106. package/esm/utils/auto-reset-event.d.ts +1 -1
  107. package/esm/utils/auto-reset-event.d.ts.map +1 -1
  108. package/esm/utils/auto-reset-event.js +2 -2
  109. package/esm/utils/base64.d.ts +23 -0
  110. package/esm/utils/base64.d.ts.map +1 -1
  111. package/esm/utils/base64.js +36 -29
  112. package/esm/utils/base64.js.map +1 -1
  113. package/package.json +19 -17
  114. package/src/adb.ts +140 -86
  115. package/src/auth.ts +27 -18
  116. package/src/backend.ts +7 -4
  117. package/src/commands/base.ts +3 -2
  118. package/src/commands/framebuffer.ts +48 -47
  119. package/src/commands/install.ts +20 -10
  120. package/src/commands/power.ts +14 -10
  121. package/src/commands/reverse.ts +53 -33
  122. package/src/commands/subprocess/command.ts +134 -0
  123. package/src/commands/subprocess/index.ts +1 -137
  124. package/src/commands/subprocess/protocols/none.ts +10 -6
  125. package/src/commands/subprocess/protocols/shell.ts +72 -39
  126. package/src/commands/subprocess/protocols/types.ts +12 -8
  127. package/src/commands/sync/index.ts +1 -1
  128. package/src/commands/sync/list.ts +63 -68
  129. package/src/commands/sync/pull.ts +53 -37
  130. package/src/commands/sync/push.ts +26 -15
  131. package/src/commands/sync/request.ts +20 -21
  132. package/src/commands/sync/response.ts +63 -53
  133. package/src/commands/sync/stat.ts +91 -90
  134. package/src/commands/sync/sync.ts +56 -34
  135. package/src/crypto.ts +61 -33
  136. package/src/features.ts +1 -1
  137. package/src/index.ts +9 -11
  138. package/src/packet.ts +40 -30
  139. package/src/socket/dispatcher.ts +119 -77
  140. package/src/socket/index.ts +1 -1
  141. package/src/socket/socket.ts +68 -26
  142. package/src/utils/auto-reset-event.ts +3 -3
  143. package/src/utils/base64.ts +75 -42
  144. package/tsconfig.build.json +1 -1
  145. package/tsconfig.build.tsbuildinfo +1 -1
  146. package/esm/stream/buffered.d.ts +0 -39
  147. package/esm/stream/buffered.d.ts.map +0 -1
  148. package/esm/stream/buffered.js +0 -143
  149. package/esm/stream/buffered.js.map +0 -1
  150. package/esm/stream/detect.d.ts +0 -2
  151. package/esm/stream/detect.d.ts.map +0 -1
  152. package/esm/stream/detect.js +0 -6
  153. package/esm/stream/detect.js.map +0 -1
  154. package/esm/stream/detect.native.d.ts +0 -240
  155. package/esm/stream/detect.native.d.ts.map +0 -1
  156. package/esm/stream/detect.native.js +0 -60
  157. package/esm/stream/detect.native.js.map +0 -1
  158. package/esm/stream/detect.polyfill.d.ts +0 -18
  159. package/esm/stream/detect.polyfill.d.ts.map +0 -1
  160. package/esm/stream/detect.polyfill.js +0 -4
  161. package/esm/stream/detect.polyfill.js.map +0 -1
  162. package/esm/stream/index.d.ts +0 -4
  163. package/esm/stream/index.d.ts.map +0 -1
  164. package/esm/stream/index.js +0 -4
  165. package/esm/stream/index.js.map +0 -1
  166. package/esm/stream/transform.d.ts +0 -124
  167. package/esm/stream/transform.d.ts.map +0 -1
  168. package/esm/stream/transform.js +0 -379
  169. package/esm/stream/transform.js.map +0 -1
  170. package/src/stream/buffered.ts +0 -168
  171. package/src/stream/detect.native.ts +0 -362
  172. package/src/stream/detect.polyfill.ts +0 -22
  173. package/src/stream/detect.ts +0 -7
  174. package/src/stream/index.ts +0 -3
  175. package/src/stream/transform.ts +0 -474
  176. package/tsconfig.test.json +0 -9
  177. package/web-streams-polyfill-4.0.0-beta.2.tgz +0 -0
@@ -1,64 +1,74 @@
1
- import Struct, { type StructAsyncDeserializeStream, type StructLike, type StructValueType } from '@yume-chan/struct';
2
- import type { AdbBufferedStream } from '../../stream/index.js';
1
+ import { type BufferedReadableStream } from "@yume-chan/stream-extra";
2
+ import Struct, {
3
+ type StructLike,
4
+ type StructValueType,
5
+ } from "@yume-chan/struct";
6
+
3
7
  import { decodeUtf8 } from "../../utils/index.js";
4
8
 
5
9
  export enum AdbSyncResponseId {
6
- Entry = 'DENT',
7
- Entry2 = 'DNT2',
8
- Lstat = 'STAT',
9
- Stat = 'STA2',
10
- Lstat2 = 'LST2',
11
- Done = 'DONE',
12
- Data = 'DATA',
13
- Ok = 'OKAY',
14
- Fail = 'FAIL',
10
+ Entry = "DENT",
11
+ Entry2 = "DNT2",
12
+ Lstat = "STAT",
13
+ Stat = "STA2",
14
+ Lstat2 = "LST2",
15
+ Done = "DONE",
16
+ Data = "DATA",
17
+ Ok = "OKAY",
18
+ Fail = "FAIL",
15
19
  }
16
20
 
17
- // DONE responses' size are always same as the request's normal response.
18
- // For example DONE responses for LIST requests are 16 bytes (same as DENT responses),
19
- // but DONE responses for STAT requests are 12 bytes (same as STAT responses)
20
- // So we need to know responses' size in advance.
21
- export class AdbSyncDoneResponse implements StructLike<AdbSyncDoneResponse> {
22
- private length: number;
23
-
24
- public readonly id = AdbSyncResponseId.Done;
21
+ export const AdbSyncFailResponse = new Struct({ littleEndian: true })
22
+ .uint32("messageLength")
23
+ .string("message", { lengthField: "messageLength" })
24
+ .postDeserialize((object) => {
25
+ throw new Error(object.message);
26
+ });
25
27
 
26
- public constructor(length: number) {
27
- this.length = length;
28
- }
29
-
30
- public async deserialize(stream: StructAsyncDeserializeStream): Promise<this> {
31
- await stream.read(this.length);
32
- return this;
28
+ export async function adbSyncReadResponse<T>(
29
+ stream: BufferedReadableStream,
30
+ id: AdbSyncResponseId,
31
+ type: StructLike<T>
32
+ ): Promise<T> {
33
+ const actualId = decodeUtf8(await stream.read(4));
34
+ switch (actualId) {
35
+ case AdbSyncResponseId.Fail:
36
+ await AdbSyncFailResponse.deserialize(stream);
37
+ throw new Error("Unreachable");
38
+ case id:
39
+ return await type.deserialize(stream);
40
+ default:
41
+ throw new Error(`Expected '${id}', but got '${actualId}'`);
33
42
  }
34
43
  }
35
44
 
36
- export const AdbSyncFailResponse =
37
- new Struct({ littleEndian: true })
38
- .uint32('messageLength')
39
- .string('message', { lengthField: 'messageLength' })
40
- .postDeserialize(object => {
41
- throw new Error(object.message);
42
- });
43
-
44
- export async function adbSyncReadResponse<T extends Record<string, StructLike<any>>>(
45
- stream: AdbBufferedStream,
46
- types: T,
47
- // When `T` is a union type, `T[keyof T]` only includes their common keys.
48
- // For example, let `type T = { a: string, b: string } | { a: string, c: string}`,
49
- // `keyof T` is `'a'`, not `'a' | 'b' | 'c'`.
50
- // However, `T extends unknown ? keyof T : never` will distribute `T`,
51
- // so returns all keys.
52
- ): Promise<StructValueType<T extends unknown ? T[keyof T] : never>> {
53
- const id = decodeUtf8(await stream.read(4));
54
-
55
- if (id === AdbSyncResponseId.Fail) {
56
- await AdbSyncFailResponse.deserialize(stream);
57
- }
58
-
59
- if (types[id]) {
60
- return types[id]!.deserialize(stream);
45
+ export async function* adbSyncReadResponses<
46
+ T extends Struct<object, PropertyKey, object, any>
47
+ >(
48
+ stream: BufferedReadableStream,
49
+ id: AdbSyncResponseId,
50
+ type: T
51
+ ): AsyncGenerator<StructValueType<T>, void, void> {
52
+ while (true) {
53
+ const actualId = decodeUtf8(await stream.read(4));
54
+ switch (actualId) {
55
+ case AdbSyncResponseId.Fail:
56
+ await AdbSyncFailResponse.deserialize(stream);
57
+ throw new Error("Unreachable");
58
+ case AdbSyncResponseId.Done:
59
+ // `DONE` responses' size are always same as the request's normal response.
60
+ //
61
+ // For example, `DONE` responses for `LIST` requests are 16 bytes (same as `DENT` responses),
62
+ // but `DONE` responses for `STAT` requests are 12 bytes (same as `STAT` responses).
63
+ await stream.read(type.size);
64
+ return;
65
+ case id:
66
+ yield await type.deserialize(stream);
67
+ break;
68
+ default:
69
+ throw new Error(
70
+ `Expected '${id}' or '${AdbSyncResponseId.Done}', but got '${actualId}'`
71
+ );
72
+ }
61
73
  }
62
-
63
- throw new Error(`Expected '${Object.keys(types).join(', ')}', but got '${id}'`);
64
74
  }
@@ -1,7 +1,11 @@
1
- import Struct, { placeholder } from '@yume-chan/struct';
2
- import type { AdbBufferedStream, WritableStreamDefaultWriter } from '../../stream/index.js';
3
- import { AdbSyncRequestId, adbSyncWriteRequest } from './request.js';
4
- import { adbSyncReadResponse, AdbSyncResponseId } from './response.js';
1
+ import {
2
+ type BufferedReadableStream,
3
+ type WritableStreamDefaultWriter,
4
+ } from "@yume-chan/stream-extra";
5
+ import Struct, { placeholder } from "@yume-chan/struct";
6
+
7
+ import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
8
+ import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js";
5
9
 
6
10
  // https://github.com/python/cpython/blob/4e581d64b8aff3e2eda99b12f080c877bb78dfca/Lib/stat.py#L36
7
11
  export enum LinuxFileType {
@@ -23,27 +27,27 @@ export interface AdbSyncStat {
23
27
  ctime?: bigint;
24
28
  }
25
29
 
26
- export const AdbSyncLstatResponse =
27
- new Struct({ littleEndian: true })
28
- .int32('mode')
29
- .int32('size')
30
- .int32('mtime')
31
- .extra({
32
- id: AdbSyncResponseId.Lstat as const,
33
- get type() { return this.mode >> 12 as LinuxFileType; },
34
- get permission() { return this.mode & 0b00001111_11111111; },
35
- })
36
- .postDeserialize((object) => {
37
- if (
38
- object.mode === 0 &&
39
- object.size === 0 &&
40
- object.mtime === 0
41
- ) {
42
- throw new Error('lstat failed');
43
- }
44
- });
45
-
46
- export type AdbSyncLstatResponse = typeof AdbSyncLstatResponse['TDeserializeResult'];
30
+ export const AdbSyncLstatResponse = new Struct({ littleEndian: true })
31
+ .int32("mode")
32
+ .int32("size")
33
+ .int32("mtime")
34
+ .extra({
35
+ id: AdbSyncResponseId.Lstat as const,
36
+ get type() {
37
+ return (this.mode >> 12) as LinuxFileType;
38
+ },
39
+ get permission() {
40
+ return this.mode & 0b00001111_11111111;
41
+ },
42
+ })
43
+ .postDeserialize((object) => {
44
+ if (object.mode === 0 && object.size === 0 && object.mtime === 0) {
45
+ throw new Error("lstat error");
46
+ }
47
+ });
48
+
49
+ export type AdbSyncLstatResponse =
50
+ typeof AdbSyncLstatResponse["TDeserializeResult"];
47
51
 
48
52
  export enum AdbSyncStatErrorCode {
49
53
  SUCCESS = 0,
@@ -69,83 +73,80 @@ export enum AdbSyncStatErrorCode {
69
73
  ETXTBSY = 26,
70
74
  }
71
75
 
72
- export const AdbSyncStatResponse =
73
- new Struct({ littleEndian: true })
74
- .uint32('error', placeholder<AdbSyncStatErrorCode>())
75
- .uint64('dev')
76
- .uint64('ino')
77
- .uint32('mode')
78
- .uint32('nlink')
79
- .uint32('uid')
80
- .uint32('gid')
81
- .uint64('size')
82
- .uint64('atime')
83
- .uint64('mtime')
84
- .uint64('ctime')
85
- .extra({
86
- id: AdbSyncResponseId.Stat as const,
87
- get type() { return this.mode >> 12 as LinuxFileType; },
88
- get permission() { return this.mode & 0b00001111_11111111; },
89
- })
90
- .postDeserialize((object) => {
91
- if (object.error) {
92
- throw new Error(AdbSyncStatErrorCode[object.error]);
93
- }
94
- });
95
-
96
- export type AdbSyncStatResponse = typeof AdbSyncStatResponse['TDeserializeResult'];
97
-
98
- const STAT_RESPONSE_TYPES = {
99
- [AdbSyncResponseId.Stat]: AdbSyncStatResponse,
100
- };
101
-
102
- const LSTAT_RESPONSE_TYPES = {
103
- [AdbSyncResponseId.Lstat]: AdbSyncLstatResponse,
104
- };
105
-
106
- const LSTAT_V2_RESPONSE_TYPES = {
107
- [AdbSyncResponseId.Lstat2]: AdbSyncStatResponse,
108
- };
76
+ export const AdbSyncStatResponse = new Struct({ littleEndian: true })
77
+ .uint32("error", placeholder<AdbSyncStatErrorCode>())
78
+ .uint64("dev")
79
+ .uint64("ino")
80
+ .uint32("mode")
81
+ .uint32("nlink")
82
+ .uint32("uid")
83
+ .uint32("gid")
84
+ .uint64("size")
85
+ .uint64("atime")
86
+ .uint64("mtime")
87
+ .uint64("ctime")
88
+ .extra({
89
+ id: AdbSyncResponseId.Stat as const,
90
+ get type() {
91
+ return (this.mode >> 12) as LinuxFileType;
92
+ },
93
+ get permission() {
94
+ return this.mode & 0b00001111_11111111;
95
+ },
96
+ })
97
+ .postDeserialize((object) => {
98
+ if (object.error) {
99
+ throw new Error(AdbSyncStatErrorCode[object.error]);
100
+ }
101
+ });
102
+
103
+ export type AdbSyncStatResponse =
104
+ typeof AdbSyncStatResponse["TDeserializeResult"];
109
105
 
110
106
  export async function adbSyncLstat(
111
- stream: AdbBufferedStream,
107
+ stream: BufferedReadableStream,
112
108
  writer: WritableStreamDefaultWriter<Uint8Array>,
113
109
  path: string,
114
- v2: boolean,
110
+ v2: boolean
115
111
  ): Promise<AdbSyncStat> {
116
- let requestId: AdbSyncRequestId.Lstat | AdbSyncRequestId.Lstat2;
117
- let responseType: typeof LSTAT_RESPONSE_TYPES | typeof LSTAT_V2_RESPONSE_TYPES;
118
-
119
112
  if (v2) {
120
- requestId = AdbSyncRequestId.Lstat2;
121
- responseType = LSTAT_V2_RESPONSE_TYPES;
113
+ await adbSyncWriteRequest(writer, AdbSyncRequestId.Lstat2, path);
114
+ return await adbSyncReadResponse(
115
+ stream,
116
+ AdbSyncResponseId.Lstat2,
117
+ AdbSyncStatResponse
118
+ );
122
119
  } else {
123
- requestId = AdbSyncRequestId.Lstat;
124
- responseType = LSTAT_RESPONSE_TYPES;
125
- }
126
-
127
- await adbSyncWriteRequest(writer, requestId, path);
128
- const response = await adbSyncReadResponse(stream, responseType);
129
-
130
- switch (response.id) {
131
- case AdbSyncResponseId.Lstat:
132
- return {
133
- mode: response.mode,
134
- size: BigInt(response.size),
135
- mtime: BigInt(response.mtime),
136
- get type() { return response.type; },
137
- get permission() { return response.permission; },
138
- };
139
- default:
140
- return response;
120
+ await adbSyncWriteRequest(writer, AdbSyncRequestId.Lstat, path);
121
+ const response = await adbSyncReadResponse(
122
+ stream,
123
+ AdbSyncResponseId.Lstat,
124
+ AdbSyncLstatResponse
125
+ );
126
+ return {
127
+ mode: response.mode,
128
+ // Convert to `BigInt` to make it compatible with `AdbSyncStatResponse`
129
+ size: BigInt(response.size),
130
+ mtime: BigInt(response.mtime),
131
+ get type() {
132
+ return response.type;
133
+ },
134
+ get permission() {
135
+ return response.permission;
136
+ },
137
+ };
141
138
  }
142
139
  }
143
140
 
144
141
  export async function adbSyncStat(
145
- stream: AdbBufferedStream,
142
+ stream: BufferedReadableStream,
146
143
  writer: WritableStreamDefaultWriter<Uint8Array>,
147
- path: string,
144
+ path: string
148
145
  ): Promise<AdbSyncStatResponse> {
149
146
  await adbSyncWriteRequest(writer, AdbSyncRequestId.Stat, path);
150
- return await adbSyncReadResponse(stream, STAT_RESPONSE_TYPES);
147
+ return await adbSyncReadResponse(
148
+ stream,
149
+ AdbSyncResponseId.Stat,
150
+ AdbSyncStatResponse
151
+ );
151
152
  }
@@ -1,14 +1,23 @@
1
- import { AutoDisposable } from '@yume-chan/event';
2
- import type { Adb } from '../../adb.js';
3
- import { AdbFeatures } from '../../features.js';
4
- import type { AdbSocket } from '../../socket/index.js';
5
- import { AdbBufferedStream, ReadableStream, WrapReadableStream, WrapWritableStream, WritableStream, WritableStreamDefaultWriter } from '../../stream/index.js';
6
- import { AutoResetEvent } from '../../utils/index.js';
7
- import { escapeArg } from "../index.js";
8
- import { adbSyncOpenDir, type AdbSyncEntry } from './list.js';
9
- import { adbSyncPull } from './pull.js';
10
- import { adbSyncPush } from './push.js';
11
- import { adbSyncLstat, adbSyncStat } from './stat.js';
1
+ import { AutoDisposable } from "@yume-chan/event";
2
+ import {
3
+ BufferedReadableStream,
4
+ WrapReadableStream,
5
+ WrapWritableStream,
6
+ type ReadableStream,
7
+ type WritableStream,
8
+ type WritableStreamDefaultWriter,
9
+ } from "@yume-chan/stream-extra";
10
+
11
+ import { type Adb } from "../../adb.js";
12
+ import { AdbFeatures } from "../../features.js";
13
+ import { type AdbSocket } from "../../socket/index.js";
14
+ import { AutoResetEvent } from "../../utils/index.js";
15
+ import { escapeArg } from "../subprocess/index.js";
16
+
17
+ import { adbSyncOpenDir, type AdbSyncEntry } from "./list.js";
18
+ import { adbSyncPull } from "./pull.js";
19
+ import { adbSyncPush } from "./push.js";
20
+ import { adbSyncLstat, adbSyncStat } from "./stat.js";
12
21
 
13
22
  /**
14
23
  * A simplified `dirname` function that only handles absolute unix paths.
@@ -16,12 +25,12 @@ import { adbSyncLstat, adbSyncStat } from './stat.js';
16
25
  * @returns the directory name of the input path
17
26
  */
18
27
  export function dirname(path: string): string {
19
- const end = path.lastIndexOf('/');
28
+ const end = path.lastIndexOf("/");
20
29
  if (end === -1) {
21
30
  throw new Error(`Invalid path`);
22
31
  }
23
32
  if (end === 0) {
24
- return '/';
33
+ return "/";
25
34
  }
26
35
  return path.substring(0, end);
27
36
  }
@@ -29,34 +38,38 @@ export function dirname(path: string): string {
29
38
  export class AdbSync extends AutoDisposable {
30
39
  protected adb: Adb;
31
40
 
32
- protected stream: AdbBufferedStream;
33
-
41
+ protected stream: BufferedReadableStream;
42
+ // Getting another writer on a locked WritableStream will throw.
43
+ // We don't want this behavior on higher-level APIs.
44
+ // So we acquire the writer early and use a blocking lock to guard it.
34
45
  protected writer: WritableStreamDefaultWriter<Uint8Array>;
35
-
36
46
  protected sendLock = this.addDisposable(new AutoResetEvent());
37
47
 
38
48
  public get supportsStat(): boolean {
39
- return this.adb.features!.includes(AdbFeatures.StatV2);
49
+ return this.adb.features.includes(AdbFeatures.StatV2);
40
50
  }
41
51
 
42
52
  public get supportsList2(): boolean {
43
- return this.adb.features!.includes(AdbFeatures.ListV2);
53
+ return this.adb.features.includes(AdbFeatures.ListV2);
44
54
  }
45
55
 
46
56
  public get fixedPushMkdir(): boolean {
47
- return this.adb.features!.includes(AdbFeatures.FixedPushMkdir);
57
+ return this.adb.features.includes(AdbFeatures.FixedPushMkdir);
48
58
  }
49
59
 
50
60
  public get needPushMkdirWorkaround(): boolean {
51
61
  // https://android.googlesource.com/platform/packages/modules/adb/+/91768a57b7138166e0a3d11f79cd55909dda7014/client/file_sync_client.cpp#1361
52
- return this.adb.features!.includes(AdbFeatures.ShellV2) && !this.fixedPushMkdir;
62
+ return (
63
+ this.adb.features.includes(AdbFeatures.ShellV2) &&
64
+ !this.fixedPushMkdir
65
+ );
53
66
  }
54
67
 
55
68
  public constructor(adb: Adb, socket: AdbSocket) {
56
69
  super();
57
70
 
58
71
  this.adb = adb;
59
- this.stream = new AdbBufferedStream(socket);
72
+ this.stream = new BufferedReadableStream(socket.readable);
60
73
  this.writer = socket.writable.getWriter();
61
74
  }
62
75
 
@@ -64,7 +77,12 @@ export class AdbSync extends AutoDisposable {
64
77
  await this.sendLock.wait();
65
78
 
66
79
  try {
67
- return adbSyncLstat(this.stream, this.writer, path, this.supportsStat);
80
+ return adbSyncLstat(
81
+ this.stream,
82
+ this.writer,
83
+ path,
84
+ this.supportsStat
85
+ );
68
86
  } finally {
69
87
  this.sendLock.notify();
70
88
  }
@@ -72,7 +90,7 @@ export class AdbSync extends AutoDisposable {
72
90
 
73
91
  public async stat(path: string) {
74
92
  if (!this.supportsStat) {
75
- throw new Error('Not supported');
93
+ throw new Error("Not supported");
76
94
  }
77
95
 
78
96
  await this.sendLock.wait();
@@ -86,7 +104,7 @@ export class AdbSync extends AutoDisposable {
86
104
 
87
105
  public async isDirectory(path: string): Promise<boolean> {
88
106
  try {
89
- await this.lstat(path + '/');
107
+ await this.lstat(path + "/");
90
108
  return true;
91
109
  } catch (e) {
92
110
  return false;
@@ -99,7 +117,12 @@ export class AdbSync extends AutoDisposable {
99
117
  await this.sendLock.wait();
100
118
 
101
119
  try {
102
- yield* adbSyncOpenDir(this.stream, this.writer, path, this.supportsList2);
120
+ yield* adbSyncOpenDir(
121
+ this.stream,
122
+ this.writer,
123
+ path,
124
+ this.supportsList2
125
+ );
103
126
  } finally {
104
127
  this.sendLock.notify();
105
128
  }
@@ -125,7 +148,7 @@ export class AdbSync extends AutoDisposable {
125
148
  await this.sendLock.wait();
126
149
  return adbSyncPull(this.stream, this.writer, filename);
127
150
  },
128
- close: async () => {
151
+ close: () => {
129
152
  this.sendLock.notify();
130
153
  },
131
154
  });
@@ -142,7 +165,7 @@ export class AdbSync extends AutoDisposable {
142
165
  public write(
143
166
  filename: string,
144
167
  mode?: number,
145
- mtime?: number,
168
+ mtime?: number
146
169
  ): WritableStream<Uint8Array> {
147
170
  return new WrapWritableStream({
148
171
  start: async () => {
@@ -151,10 +174,10 @@ export class AdbSync extends AutoDisposable {
151
174
  if (this.needPushMkdirWorkaround) {
152
175
  // It may fail if the path is already existed.
153
176
  // Ignore the result.
154
- // TODO: sync: test this
177
+ // TODO: sync: test push mkdir workaround (need an Android 8 device)
155
178
  await this.adb.subprocess.spawnAndWait([
156
- 'mkdir',
157
- '-p',
179
+ "mkdir",
180
+ "-p",
158
181
  escapeArg(dirname(filename)),
159
182
  ]);
160
183
  }
@@ -164,18 +187,17 @@ export class AdbSync extends AutoDisposable {
164
187
  this.writer,
165
188
  filename,
166
189
  mode,
167
- mtime,
190
+ mtime
168
191
  );
169
192
  },
170
- close: async () => {
193
+ close: () => {
171
194
  this.sendLock.notify();
172
- }
195
+ },
173
196
  });
174
197
  }
175
198
 
176
199
  public override async dispose() {
177
200
  super.dispose();
178
- await this.stream.close();
179
201
  await this.writer.close();
180
202
  }
181
203
  }