mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-05 10:49:24 +02:00
feat: stream migrate done
This commit is contained in:
parent
ef57682ec3
commit
2a5843eb20
14 changed files with 228 additions and 150 deletions
|
@ -94,8 +94,8 @@ function _Connect(): JSX.Element | null {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const addTcpBackend = useCallback(() => {
|
const addTcpBackend = useCallback(() => {
|
||||||
const address = window.prompt('Enter the address of device');
|
const host = window.prompt('Enter the address of device');
|
||||||
if (!address) {
|
if (!host) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,8 +108,18 @@ function _Connect(): JSX.Element | null {
|
||||||
|
|
||||||
setTcpBackendList(list => {
|
setTcpBackendList(list => {
|
||||||
const copy = list.slice();
|
const copy = list.slice();
|
||||||
copy.push(new AdbDirectSocketsBackend(address, portNumber));
|
copy.push(new AdbDirectSocketsBackend(host, portNumber));
|
||||||
window.localStorage.setItem('tcp-backend-list', JSON.stringify(copy.map(x => ({ address: x.address, port: x.port }))));
|
window.localStorage.setItem(
|
||||||
|
'tcp-backend-list',
|
||||||
|
JSON.stringify(
|
||||||
|
copy.map(
|
||||||
|
x => ({
|
||||||
|
address: x.host,
|
||||||
|
port: x.port
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
return copy;
|
return copy;
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
@ -130,13 +140,14 @@ function _Connect(): JSX.Element | null {
|
||||||
const connect = useCallback(async () => {
|
const connect = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
if (selectedBackend) {
|
if (selectedBackend) {
|
||||||
const device = new Adb(selectedBackend, logger.logger);
|
let device: Adb | undefined;
|
||||||
try {
|
try {
|
||||||
setConnecting(true);
|
setConnecting(true);
|
||||||
await device.connect(CredentialStore);
|
device = await Adb.connect(selectedBackend, logger.logger);
|
||||||
|
await device.authenticate(CredentialStore);
|
||||||
globalState.setDevice(device);
|
globalState.setDevice(device);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
device.dispose();
|
device?.dispose();
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ module.exports = withMDX({
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
productionBrowserSourceMaps: true,
|
productionBrowserSourceMaps: true,
|
||||||
experimental: {
|
experimental: {
|
||||||
|
// Workaround https://github.com/vercel/next.js/issues/33914
|
||||||
esmExternals: 'loose',
|
esmExternals: 'loose',
|
||||||
},
|
},
|
||||||
publicRuntimeConfig: {
|
publicRuntimeConfig: {
|
||||||
|
@ -35,6 +36,8 @@ module.exports = withMDX({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
config.experiments.topLevelAwait = true;
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
async headers() {
|
async headers() {
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"@yume-chan/struct": "^0.0.10",
|
"@yume-chan/struct": "^0.0.10",
|
||||||
"mobx": "^6.3.13",
|
"mobx": "^6.3.13",
|
||||||
"mobx-react-lite": "^3.2.3",
|
"mobx-react-lite": "^3.2.3",
|
||||||
"next": "12.0.11-canary.9",
|
"next": "12.1.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"streamsaver": "^2.0.5",
|
"streamsaver": "^2.0.5",
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
"@next/mdx": "^11.1.2",
|
"@next/mdx": "^11.1.2",
|
||||||
"@types/react": "17.0.27",
|
"@types/react": "17.0.27",
|
||||||
"eslint": "8.8.0",
|
"eslint": "8.8.0",
|
||||||
"eslint-config-next": "12.0.11-canary.6",
|
"eslint-config-next": "12.1.0",
|
||||||
"typescript": "^4.5.5"
|
"typescript": "^4.5.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,8 @@ import { FileIconType } from "@fluentui/react-file-type-icons";
|
||||||
import { getFileTypeIconNameFromExtensionOrType } from '@fluentui/react-file-type-icons/lib-commonjs/getFileTypeIconProps';
|
import { getFileTypeIconNameFromExtensionOrType } from '@fluentui/react-file-type-icons/lib-commonjs/getFileTypeIconProps';
|
||||||
import { DEFAULT_BASE_URL as FILE_TYPE_ICONS_BASE_URL } from '@fluentui/react-file-type-icons/lib-commonjs/initializeFileTypeIcons';
|
import { DEFAULT_BASE_URL as FILE_TYPE_ICONS_BASE_URL } from '@fluentui/react-file-type-icons/lib-commonjs/initializeFileTypeIcons';
|
||||||
import { useConst } from '@fluentui/react-hooks';
|
import { useConst } from '@fluentui/react-hooks';
|
||||||
import { AdbSyncEntryResponse, ADB_SYNC_MAX_PACKET_SIZE, LinuxFileType } from '@yume-chan/adb';
|
import { AdbSyncEntryResponse, ADB_SYNC_MAX_PACKET_SIZE, ChunkStream, LinuxFileType, ReadableStream, TransformStream } from '@yume-chan/adb';
|
||||||
|
import { ExtractViewBufferStream } from "@yume-chan/adb-backend-direct-sockets";
|
||||||
import { action, autorun, makeAutoObservable, observable, runInAction } from "mobx";
|
import { action, autorun, makeAutoObservable, observable, runInAction } from "mobx";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { NextPage } from "next";
|
import { NextPage } from "next";
|
||||||
|
@ -11,10 +12,10 @@ import getConfig from "next/config";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import Router, { useRouter } from "next/router";
|
import Router, { useRouter } from "next/router";
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { CommandBar, NoSsr } from '../components';
|
import { CommandBar, NoSsr } from '../components';
|
||||||
import { globalState } from '../state';
|
import { globalState } from '../state';
|
||||||
import { asyncEffect, chunkFile, formatSize, formatSpeed, Icons, pickFile, RouteStackProps } from '../utils';
|
import { asyncEffect, formatSize, formatSpeed, Icons, pickFile, RouteStackProps } from '../utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Because of internal buffer of upstream/downstream streams,
|
* Because of internal buffer of upstream/downstream streams,
|
||||||
|
@ -186,12 +187,12 @@ class FileManagerState {
|
||||||
const sync = await globalState.device!.sync();
|
const sync = await globalState.device!.sync();
|
||||||
try {
|
try {
|
||||||
const itemPath = path.resolve(this.path, this.selectedItems[0].name!);
|
const itemPath = path.resolve(this.path, this.selectedItems[0].name!);
|
||||||
const readableStream = sync.read(itemPath);
|
const readableStream = await sync.read(itemPath);
|
||||||
|
|
||||||
const writeableStream = StreamSaver!.createWriteStream(this.selectedItems[0].name!, {
|
const writeable = StreamSaver!.createWriteStream(this.selectedItems[0].name!, {
|
||||||
size: this.selectedItems[0].size,
|
size: this.selectedItems[0].size,
|
||||||
});
|
});
|
||||||
await readableStream.pipeTo(writeableStream);
|
await readableStream.pipeTo(writeable);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
globalState.showErrorDialog(e instanceof Error ? e.message : `${e}`);
|
globalState.showErrorDialog(e instanceof Error ? e.message : `${e}`);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -490,17 +491,18 @@ class FileManagerState {
|
||||||
}), 1000);
|
}), 1000);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const writable = sync.write(
|
await (file.stream() as unknown as ReadableStream<Uint8Array>)
|
||||||
itemPath,
|
.pipeThrough(new ExtractViewBufferStream())
|
||||||
chunkFile(file, ADB_SYNC_MAX_PACKET_SIZE),
|
.pipeThrough(new ChunkStream(ADB_SYNC_MAX_PACKET_SIZE))
|
||||||
(LinuxFileType.File << 12) | 0o666,
|
.pipeThrough(new ProgressStream(action((uploaded) => {
|
||||||
file.lastModified / 1000,
|
|
||||||
action((uploaded) => {
|
|
||||||
this.uploadedSize = uploaded;
|
this.uploadedSize = uploaded;
|
||||||
}),
|
})))
|
||||||
);
|
.pipeTo(sync.write(
|
||||||
const readable: ReadableStream<ArrayBuffer> = file.stream();
|
itemPath,
|
||||||
readable.pipeThrough();
|
(LinuxFileType.File << 12) | 0o666,
|
||||||
|
file.lastModified / 1000,
|
||||||
|
));
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.uploadSpeed = this.uploadedSize - this.debouncedUploadedSize;
|
this.uploadSpeed = this.uploadedSize - this.debouncedUploadedSize;
|
||||||
this.debouncedUploadedSize = this.uploadedSize;
|
this.debouncedUploadedSize = this.uploadedSize;
|
||||||
|
@ -571,8 +573,8 @@ const FileManager: NextPage = (): JSX.Element | null => {
|
||||||
const previewImage = useCallback(async (path: string) => {
|
const previewImage = useCallback(async (path: string) => {
|
||||||
const sync = await globalState.device!.sync();
|
const sync = await globalState.device!.sync();
|
||||||
try {
|
try {
|
||||||
const readableStream = createReadableStreamFromBufferIterator(sync.read(path));
|
const readable = await sync.read(path);
|
||||||
const response = new Response(readableStream);
|
const response = new Response(readable);
|
||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
const url = window.URL.createObjectURL(blob);
|
const url = window.URL.createObjectURL(blob);
|
||||||
setPreviewUrl(url);
|
setPreviewUrl(url);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { DefaultButton, ProgressIndicator, Stack } from "@fluentui/react";
|
import { DefaultButton, ProgressIndicator, Stack } from "@fluentui/react";
|
||||||
import { ADB_SYNC_MAX_PACKET_SIZE } from "@yume-chan/adb";
|
import { ADB_SYNC_MAX_PACKET_SIZE, ChunkStream, ReadableStream } from "@yume-chan/adb";
|
||||||
import { makeAutoObservable, observable, runInAction } from "mobx";
|
import { ExtractViewBufferStream } from "@yume-chan/adb-backend-direct-sockets";
|
||||||
|
import { action, makeAutoObservable, observable, runInAction } from "mobx";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { NextPage } from "next";
|
import { NextPage } from "next";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
|
@ -58,10 +59,10 @@ class InstallPageState {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
setTimeout(handler);
|
await (file.stream() as unknown as ReadableStream<Uint8Array>)
|
||||||
const readable = file.stream();
|
.pipeThrough(new ExtractViewBufferStream())
|
||||||
await globalState.device!.install(chunkFile(file, AdbSyncMaxPacketSize), uploaded => {
|
.pipeThrough(new ChunkStream(ADB_SYNC_MAX_PACKET_SIZE))
|
||||||
runInAction(() => {
|
.pipeThrough(new ProgressStream(action((uploaded) => {
|
||||||
if (uploaded !== file.size) {
|
if (uploaded !== file.size) {
|
||||||
this.progress = {
|
this.progress = {
|
||||||
filename: file.name,
|
filename: file.name,
|
||||||
|
@ -79,8 +80,8 @@ class InstallPageState {
|
||||||
value: 0.8,
|
value: 0.8,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
})))
|
||||||
});
|
.pipeTo(globalState.device!.install());
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.progress = {
|
this.progress = {
|
||||||
|
|
|
@ -17,9 +17,6 @@ export class GlobalState {
|
||||||
|
|
||||||
setDevice(device: Adb | undefined) {
|
setDevice(device: Adb | undefined) {
|
||||||
this.device = device;
|
this.device = device;
|
||||||
device?.onDisconnected(() => {
|
|
||||||
this.setDevice(undefined);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showErrorDialog(message: string) {
|
showErrorDialog(message: string) {
|
||||||
|
|
112
common/config/rush/pnpm-lock.yaml
generated
112
common/config/rush/pnpm-lock.yaml
generated
|
@ -35,7 +35,7 @@ specifiers:
|
||||||
bluebird: ^3.7.2
|
bluebird: ^3.7.2
|
||||||
clsx: ^1.1.1
|
clsx: ^1.1.1
|
||||||
eslint: 8.8.0
|
eslint: 8.8.0
|
||||||
eslint-config-next: 12.0.11-canary.6
|
eslint-config-next: 12.1.0
|
||||||
file-loader: ^6.2.0
|
file-loader: ^6.2.0
|
||||||
gh-release-fetch: ^2.0.4
|
gh-release-fetch: ^2.0.4
|
||||||
jest: ^26.6.3
|
jest: ^26.6.3
|
||||||
|
@ -43,7 +43,7 @@ specifiers:
|
||||||
mini-svg-data-uri: ~1.3.3
|
mini-svg-data-uri: ~1.3.3
|
||||||
mobx: ^6.3.13
|
mobx: ^6.3.13
|
||||||
mobx-react-lite: ^3.2.3
|
mobx-react-lite: ^3.2.3
|
||||||
next: 12.0.11-canary.9
|
next: 12.1.0
|
||||||
node-fetch: ~2.6.1
|
node-fetch: ~2.6.1
|
||||||
plantuml-encoder: ~1.4.0
|
plantuml-encoder: ~1.4.0
|
||||||
react: ^17.0.2
|
react: ^17.0.2
|
||||||
|
@ -94,7 +94,7 @@ dependencies:
|
||||||
bluebird: 3.7.2
|
bluebird: 3.7.2
|
||||||
clsx: 1.1.1
|
clsx: 1.1.1
|
||||||
eslint: 8.8.0
|
eslint: 8.8.0
|
||||||
eslint-config-next: 12.0.11-canary.6_6a190f5566611a51beae5b8059e6f717
|
eslint-config-next: 12.1.0_eslint@8.8.0+next@12.1.0
|
||||||
file-loader: 6.2.0
|
file-loader: 6.2.0
|
||||||
gh-release-fetch: 2.0.6
|
gh-release-fetch: 2.0.6
|
||||||
jest: 26.6.3
|
jest: 26.6.3
|
||||||
|
@ -102,7 +102,7 @@ dependencies:
|
||||||
mini-svg-data-uri: 1.3.3
|
mini-svg-data-uri: 1.3.3
|
||||||
mobx: 6.3.13
|
mobx: 6.3.13
|
||||||
mobx-react-lite: 3.2.3_96b0034b8b6bfac1b4cc60715db17f02
|
mobx-react-lite: 3.2.3_96b0034b8b6bfac1b4cc60715db17f02
|
||||||
next: 12.0.11-canary.9_react-dom@17.0.2+react@17.0.2
|
next: 12.1.0_react-dom@17.0.2+react@17.0.2
|
||||||
node-fetch: 2.6.7
|
node-fetch: 2.6.7
|
||||||
plantuml-encoder: 1.4.0
|
plantuml-encoder: 1.4.0
|
||||||
react: 17.0.2
|
react: 17.0.2
|
||||||
|
@ -2988,12 +2988,12 @@ packages:
|
||||||
resolution: {integrity: sha512-vKbuG3Mcbc4kkNAcIE13aIv5KoI2g+tHFFIZnFhtUilpYHc0VsMd4Fw7Jz81A8AB7L3wWu3OZB2CNiRnr1a3ew==}
|
resolution: {integrity: sha512-vKbuG3Mcbc4kkNAcIE13aIv5KoI2g+tHFFIZnFhtUilpYHc0VsMd4Fw7Jz81A8AB7L3wWu3OZB2CNiRnr1a3ew==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@next/env/12.0.11-canary.9:
|
/@next/env/12.1.0:
|
||||||
resolution: {integrity: sha512-mdpsKiYCmYSSJQepsi8cJ6WDvsUYgeHLH4BhwMJhDGcQw7updHGKERZ8CgnaCMbU0q3yf9hl2n7oN9gv2U9E4w==}
|
resolution: {integrity: sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@next/eslint-plugin-next/12.0.11-canary.6:
|
/@next/eslint-plugin-next/12.1.0:
|
||||||
resolution: {integrity: sha512-w5er84deDP+c6/8hKBXHXALqkEQr+dgXE0F75UIXK1otBKFb+agntqN5RfyXMWJUzpWU2+32kuFmBEDZAoHjUw==}
|
resolution: {integrity: sha512-WFiyvSM2G5cQmh32t/SiQuJ+I2O+FHVlK/RFw5b1565O2kEM/36EXncjt88Pa+X5oSc+1SS+tWxowWJd1lqI+g==}
|
||||||
dependencies:
|
dependencies:
|
||||||
glob: 7.1.7
|
glob: 7.1.7
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -3008,88 +3008,88 @@ packages:
|
||||||
'@mdx-js/react': 1.6.22_react@17.0.2
|
'@mdx-js/react': 1.6.22_react@17.0.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@next/swc-android-arm64/12.0.11-canary.9:
|
/@next/swc-android-arm64/12.1.0:
|
||||||
resolution: {integrity: sha512-9TYW6kRsNycWoP7zHp1FOdTvoupBEe4xlSiprDJQvRB19/Ms/6M1MvSJUhBLQ2DH5lExldF/jP2J6vALVkTuZg==}
|
resolution: {integrity: sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [android]
|
os: [android]
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-darwin-arm64/12.0.11-canary.9:
|
/@next/swc-darwin-arm64/12.1.0:
|
||||||
resolution: {integrity: sha512-AT7LGJMwWVBoftUiIHGzD8/HKF2mHxVRJrQJ293ibMK4RMnPK1iSNn1kI/5eKMw3jCPEG/yUGEZupP7NYYI2zA==}
|
resolution: {integrity: sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-darwin-x64/12.0.11-canary.9:
|
/@next/swc-darwin-x64/12.1.0:
|
||||||
resolution: {integrity: sha512-+MER8YoermGDL7pLSteYTnvW9zz7GriLcVotnMt3ODg4QGHk7bope4X7CdW9zmItvDC1f5VGCiKjBqg8TpEGNA==}
|
resolution: {integrity: sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-linux-arm-gnueabihf/12.0.11-canary.9:
|
/@next/swc-linux-arm-gnueabihf/12.1.0:
|
||||||
resolution: {integrity: sha512-2x+j+pP7Iq6IjZ1mXxxfczVg2TEaQeZJL8HBBL+JxIi7f8l178El1uMg66SLIdr/k3H6mLp25X+Abl0NP33cew==}
|
resolution: {integrity: sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-linux-arm64-gnu/12.0.11-canary.9:
|
/@next/swc-linux-arm64-gnu/12.1.0:
|
||||||
resolution: {integrity: sha512-02HwAx0CFVmKNTDScLqvQfLEORhDguB6IXP1Gvht+2pDkFUWfWYDqba5tPaHOIUKCeWNRfJIRR3eFy/Pp1erPA==}
|
resolution: {integrity: sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-linux-arm64-musl/12.0.11-canary.9:
|
/@next/swc-linux-arm64-musl/12.1.0:
|
||||||
resolution: {integrity: sha512-IqRWieX1hs2ovLa4Jp0XYtEiHdYPljHpqONOOaU5BuJlZcLZUdojR17jvXMCm0jTvL1tXVAV2Dez6V/LYsFrTw==}
|
resolution: {integrity: sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-linux-x64-gnu/12.0.11-canary.9:
|
/@next/swc-linux-x64-gnu/12.1.0:
|
||||||
resolution: {integrity: sha512-J2c3fzkwmUeZgX8OtyjeM6qi4jzKZUk7L9fdDdiHhnzysUQk4Lsh7c4h2peYWwu9XAqZ52vSmeYwj2A/rmArbQ==}
|
resolution: {integrity: sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-linux-x64-musl/12.0.11-canary.9:
|
/@next/swc-linux-x64-musl/12.1.0:
|
||||||
resolution: {integrity: sha512-CmbURYTzg70pZIC1rQGNTSY2rJnblM6bIKBTYz3RcRgxhbTEZk3/YaE7D7ttALvJfJCRaAuGYjaOet52eqvOIg==}
|
resolution: {integrity: sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-win32-arm64-msvc/12.0.11-canary.9:
|
/@next/swc-win32-arm64-msvc/12.1.0:
|
||||||
resolution: {integrity: sha512-yGBW252SDphtlrsY+s4AvhfYE6S6Y2hsUbAiTQsAGugXFOwqXNPEoM2A5G2FG1yG/TUEIpreIWAB7dUO3E7/Hg==}
|
resolution: {integrity: sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-win32-ia32-msvc/12.0.11-canary.9:
|
/@next/swc-win32-ia32-msvc/12.1.0:
|
||||||
resolution: {integrity: sha512-E/eMBTfOKr3ya6S16jVKsSFR+UD/QuiwGyYx1qX0Jaq9pswx9gwi7rou4geU3sRdJXJqeBAQYFs6VfDLbMTIxw==}
|
resolution: {integrity: sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@next/swc-win32-x64-msvc/12.0.11-canary.9:
|
/@next/swc-win32-x64-msvc/12.1.0:
|
||||||
resolution: {integrity: sha512-8+7AG45la2Yv6oDgCemuueNVOojbrDC1zXxdXfMIMkkj3JFHuaYR/T4Iphn09SOjg1TE7M/fzD9L1VCCYt8mQQ==}
|
resolution: {integrity: sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
@ -6048,8 +6048,8 @@ packages:
|
||||||
source-map: 0.6.1
|
source-map: 0.6.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/eslint-config-next/12.0.11-canary.6_473fdad0735444e3ca85f64cbcb6271e:
|
/eslint-config-next/12.1.0_a833109067da92148152ff2f5707ab26:
|
||||||
resolution: {integrity: sha512-2OAar5wLCvHQdu8qQLV7i+aMcDfPWSJRhGfNH2gHPyF3H3+o0gowHv1ZffYahXPSOgS4vqdXlq+edNLcVYBFSA==}
|
resolution: {integrity: sha512-tBhuUgoDITcdcM7xFvensi9I5WTI4dnvH4ETGRg1U8ZKpXrZsWQFdOKIDzR3RLP5HR3xXrLviaMM4c3zVoE/pA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^7.23.0 || ^8.0.0
|
eslint: ^7.23.0 || ^8.0.0
|
||||||
next: '>=10.2.0'
|
next: '>=10.2.0'
|
||||||
|
@ -6058,7 +6058,7 @@ packages:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@next/eslint-plugin-next': 12.0.11-canary.6
|
'@next/eslint-plugin-next': 12.1.0
|
||||||
'@rushstack/eslint-patch': 1.1.0
|
'@rushstack/eslint-patch': 1.1.0
|
||||||
'@typescript-eslint/parser': 5.12.0_eslint@8.8.0+typescript@4.5.5
|
'@typescript-eslint/parser': 5.12.0_eslint@8.8.0+typescript@4.5.5
|
||||||
eslint: 8.8.0
|
eslint: 8.8.0
|
||||||
|
@ -6068,14 +6068,14 @@ packages:
|
||||||
eslint-plugin-jsx-a11y: 6.5.1_eslint@8.8.0
|
eslint-plugin-jsx-a11y: 6.5.1_eslint@8.8.0
|
||||||
eslint-plugin-react: 7.28.0_eslint@8.8.0
|
eslint-plugin-react: 7.28.0_eslint@8.8.0
|
||||||
eslint-plugin-react-hooks: 4.3.0_eslint@8.8.0
|
eslint-plugin-react-hooks: 4.3.0_eslint@8.8.0
|
||||||
next: 12.0.11-canary.9_react-dom@17.0.2+react@17.0.2
|
next: 12.1.0_react-dom@17.0.2+react@17.0.2
|
||||||
typescript: 4.5.5
|
typescript: 4.5.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/eslint-config-next/12.0.11-canary.6_6a190f5566611a51beae5b8059e6f717:
|
/eslint-config-next/12.1.0_eslint@8.8.0+next@12.1.0:
|
||||||
resolution: {integrity: sha512-2OAar5wLCvHQdu8qQLV7i+aMcDfPWSJRhGfNH2gHPyF3H3+o0gowHv1ZffYahXPSOgS4vqdXlq+edNLcVYBFSA==}
|
resolution: {integrity: sha512-tBhuUgoDITcdcM7xFvensi9I5WTI4dnvH4ETGRg1U8ZKpXrZsWQFdOKIDzR3RLP5HR3xXrLviaMM4c3zVoE/pA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^7.23.0 || ^8.0.0
|
eslint: ^7.23.0 || ^8.0.0
|
||||||
next: '>=10.2.0'
|
next: '>=10.2.0'
|
||||||
|
@ -6084,7 +6084,7 @@ packages:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@next/eslint-plugin-next': 12.0.11-canary.6
|
'@next/eslint-plugin-next': 12.1.0
|
||||||
'@rushstack/eslint-patch': 1.1.0
|
'@rushstack/eslint-patch': 1.1.0
|
||||||
'@typescript-eslint/parser': 5.12.0_eslint@8.8.0
|
'@typescript-eslint/parser': 5.12.0_eslint@8.8.0
|
||||||
eslint: 8.8.0
|
eslint: 8.8.0
|
||||||
|
@ -6094,7 +6094,7 @@ packages:
|
||||||
eslint-plugin-jsx-a11y: 6.5.1_eslint@8.8.0
|
eslint-plugin-jsx-a11y: 6.5.1_eslint@8.8.0
|
||||||
eslint-plugin-react: 7.28.0_eslint@8.8.0
|
eslint-plugin-react: 7.28.0_eslint@8.8.0
|
||||||
eslint-plugin-react-hooks: 4.3.0_eslint@8.8.0
|
eslint-plugin-react-hooks: 4.3.0_eslint@8.8.0
|
||||||
next: 12.0.11-canary.9_react-dom@17.0.2+react@17.0.2
|
next: 12.1.0_react-dom@17.0.2+react@17.0.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -9304,13 +9304,13 @@ packages:
|
||||||
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/next/12.0.11-canary.9_react-dom@17.0.2+react@17.0.2:
|
/next/12.1.0_react-dom@17.0.2+react@17.0.2:
|
||||||
resolution: {integrity: sha512-lsUSsBiuf3QDKX5BCYr33Nv31kZDaHjbKXmi9S299LXdsv1S8z4cQQ/DHTziwSZ7Rtp25I0NzOmBmZAj8jvBkQ==}
|
resolution: {integrity: sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q==}
|
||||||
engines: {node: '>=12.22.0'}
|
engines: {node: '>=12.22.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
fibers: '>= 3.1.0'
|
fibers: '>= 3.1.0'
|
||||||
node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0
|
node-sass: ^6.0.0 || ^7.0.0
|
||||||
react: ^17.0.2 || ^18.0.0-0
|
react: ^17.0.2 || ^18.0.0-0
|
||||||
react-dom: ^17.0.2 || ^18.0.0-0
|
react-dom: ^17.0.2 || ^18.0.0-0
|
||||||
sass: ^1.3.0
|
sass: ^1.3.0
|
||||||
|
@ -9322,7 +9322,7 @@ packages:
|
||||||
sass:
|
sass:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@next/env': 12.0.11-canary.9
|
'@next/env': 12.1.0
|
||||||
caniuse-lite: 1.0.30001312
|
caniuse-lite: 1.0.30001312
|
||||||
postcss: 8.4.5
|
postcss: 8.4.5
|
||||||
react: 17.0.2
|
react: 17.0.2
|
||||||
|
@ -9330,17 +9330,17 @@ packages:
|
||||||
styled-jsx: 5.0.0_react@17.0.2
|
styled-jsx: 5.0.0_react@17.0.2
|
||||||
use-subscription: 1.5.1_react@17.0.2
|
use-subscription: 1.5.1_react@17.0.2
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@next/swc-android-arm64': 12.0.11-canary.9
|
'@next/swc-android-arm64': 12.1.0
|
||||||
'@next/swc-darwin-arm64': 12.0.11-canary.9
|
'@next/swc-darwin-arm64': 12.1.0
|
||||||
'@next/swc-darwin-x64': 12.0.11-canary.9
|
'@next/swc-darwin-x64': 12.1.0
|
||||||
'@next/swc-linux-arm-gnueabihf': 12.0.11-canary.9
|
'@next/swc-linux-arm-gnueabihf': 12.1.0
|
||||||
'@next/swc-linux-arm64-gnu': 12.0.11-canary.9
|
'@next/swc-linux-arm64-gnu': 12.1.0
|
||||||
'@next/swc-linux-arm64-musl': 12.0.11-canary.9
|
'@next/swc-linux-arm64-musl': 12.1.0
|
||||||
'@next/swc-linux-x64-gnu': 12.0.11-canary.9
|
'@next/swc-linux-x64-gnu': 12.1.0
|
||||||
'@next/swc-linux-x64-musl': 12.0.11-canary.9
|
'@next/swc-linux-x64-musl': 12.1.0
|
||||||
'@next/swc-win32-arm64-msvc': 12.0.11-canary.9
|
'@next/swc-win32-arm64-msvc': 12.1.0
|
||||||
'@next/swc-win32-ia32-msvc': 12.0.11-canary.9
|
'@next/swc-win32-ia32-msvc': 12.1.0
|
||||||
'@next/swc-win32-x64-msvc': 12.0.11-canary.9
|
'@next/swc-win32-x64-msvc': 12.1.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
- babel-plugin-macros
|
- babel-plugin-macros
|
||||||
|
@ -13293,7 +13293,7 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
file:projects/demo.tgz_@mdx-js+react@1.6.22:
|
file:projects/demo.tgz_@mdx-js+react@1.6.22:
|
||||||
resolution: {integrity: sha512-Np2YG0x2SP6d561O/JW305uxFsEbG59HfJrlEh/SoiZeB5S1prxUoYKbs3oVLEcnJ9RlzNpxDwqT4sBGIgu1sA==, tarball: file:projects/demo.tgz}
|
resolution: {integrity: sha512-Rjd2nSA/9Gu41TKCWSKZM9bMVXqUFoWr30etKv07GGFP1NVkM8sWcH9bPezqiQxXRcZ5eMXet47PSS6Db8Qmqg==, tarball: file:projects/demo.tgz}
|
||||||
id: file:projects/demo.tgz
|
id: file:projects/demo.tgz
|
||||||
name: '@rush-temp/demo'
|
name: '@rush-temp/demo'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
|
@ -13308,10 +13308,10 @@ packages:
|
||||||
'@types/react': 17.0.27
|
'@types/react': 17.0.27
|
||||||
'@yume-chan/async': 2.1.4
|
'@yume-chan/async': 2.1.4
|
||||||
eslint: 8.8.0
|
eslint: 8.8.0
|
||||||
eslint-config-next: 12.0.11-canary.6_473fdad0735444e3ca85f64cbcb6271e
|
eslint-config-next: 12.1.0_a833109067da92148152ff2f5707ab26
|
||||||
mobx: 6.3.13
|
mobx: 6.3.13
|
||||||
mobx-react-lite: 3.2.3_96b0034b8b6bfac1b4cc60715db17f02
|
mobx-react-lite: 3.2.3_96b0034b8b6bfac1b4cc60715db17f02
|
||||||
next: 12.0.11-canary.9_react-dom@17.0.2+react@17.0.2
|
next: 12.1.0_react-dom@17.0.2+react@17.0.2
|
||||||
react: 17.0.2
|
react: 17.0.2
|
||||||
react-dom: 17.0.2_react@17.0.2
|
react-dom: 17.0.2_react@17.0.2
|
||||||
streamsaver: 2.0.6
|
streamsaver: 2.0.6
|
||||||
|
|
|
@ -205,8 +205,8 @@ export class Adb {
|
||||||
return stdout;
|
return stdout;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async install(apk: ReadableStream<ArrayBuffer>): Promise<void> {
|
public install() {
|
||||||
return await install(this, apk);
|
return install(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sync(): Promise<AdbSync> {
|
public async sync(): Promise<AdbSync> {
|
||||||
|
|
|
@ -1,22 +1,32 @@
|
||||||
import { Adb } from "../adb";
|
import { Adb } from "../adb";
|
||||||
import { ReadableStream } from "../utils";
|
import { HookWritableStream, WritableStream } from "../utils";
|
||||||
import { escapeArg } from "./subprocess";
|
import { escapeArg } from "./subprocess";
|
||||||
|
import { AdbSync } from "./sync";
|
||||||
|
|
||||||
export async function install(
|
export function install(
|
||||||
adb: Adb,
|
adb: Adb,
|
||||||
apk: ReadableStream<ArrayBuffer>,
|
): WritableStream<ArrayBuffer> {
|
||||||
): Promise<void> {
|
|
||||||
const filename = `/data/local/tmp/${Math.random().toString().substring(2)}.apk`;
|
const filename = `/data/local/tmp/${Math.random().toString().substring(2)}.apk`;
|
||||||
|
|
||||||
// Upload apk file to tmp folder
|
return new HookWritableStream<ArrayBuffer, WritableStream<ArrayBuffer>, AdbSync>({
|
||||||
const sync = await adb.sync();
|
async start() {
|
||||||
const writable = sync.write(filename, undefined, undefined);
|
// Upload apk file to tmp folder
|
||||||
await apk.pipeTo(writable);
|
const sync = await adb.sync();
|
||||||
sync.dispose();
|
const writable = sync.write(filename, undefined, undefined);
|
||||||
|
|
||||||
// Invoke `pm install` to install it
|
return {
|
||||||
await adb.subprocess.spawnAndWaitLegacy(['pm', 'install', escapeArg(filename)]);
|
writable,
|
||||||
|
state: sync,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async close(sync) {
|
||||||
|
sync.dispose();
|
||||||
|
|
||||||
// Remove the temp file
|
// Invoke `pm install` to install it
|
||||||
await adb.rm(filename);
|
await adb.subprocess.spawnAndWaitLegacy(['pm', 'install', escapeArg(filename)]);
|
||||||
|
|
||||||
|
// Remove the temp file
|
||||||
|
await adb.rm(filename);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Adb } from '../../adb';
|
||||||
import { AdbFeatures } from '../../features';
|
import { AdbFeatures } from '../../features';
|
||||||
import { AdbSocket } from '../../socket';
|
import { AdbSocket } from '../../socket';
|
||||||
import { AdbBufferedStream } from '../../stream';
|
import { AdbBufferedStream } from '../../stream';
|
||||||
import { AutoResetEvent, ReadableStream, TransformStream, WritableStream, WritableStreamDefaultWriter } from '../../utils';
|
import { AutoResetEvent, HookWritableStream, ReadableStream, TransformStream, WritableStream, WritableStreamDefaultWriter } from '../../utils';
|
||||||
import { AdbSyncEntryResponse, adbSyncOpenDir } from './list';
|
import { AdbSyncEntryResponse, adbSyncOpenDir } from './list';
|
||||||
import { adbSyncPull } from './pull';
|
import { adbSyncPull } from './pull';
|
||||||
import { adbSyncPush } from './push';
|
import { adbSyncPush } from './push';
|
||||||
|
@ -118,31 +118,29 @@ export class AdbSync extends AutoDisposable {
|
||||||
*
|
*
|
||||||
* If the promise doesn't resolve immediately, it means the sync object is busy processing another command.
|
* If the promise doesn't resolve immediately, it means the sync object is busy processing another command.
|
||||||
*/
|
*/
|
||||||
public async write(
|
public write(
|
||||||
filename: string,
|
filename: string,
|
||||||
mode?: number,
|
mode?: number,
|
||||||
mtime?: number,
|
mtime?: number,
|
||||||
): Promise<WritableStream<ArrayBuffer>> {
|
): WritableStream<ArrayBuffer> {
|
||||||
await this.sendLock.wait();
|
return new HookWritableStream({
|
||||||
|
start: async () => {
|
||||||
const writable = adbSyncPush(
|
await this.sendLock.wait();
|
||||||
this.stream,
|
return {
|
||||||
this.writer,
|
writable: adbSyncPush(
|
||||||
filename,
|
this.stream,
|
||||||
mode,
|
this.writer,
|
||||||
mtime,
|
filename,
|
||||||
);
|
mode,
|
||||||
|
mtime,
|
||||||
const lockStream = new TransformStream<ArrayBuffer, ArrayBuffer>();
|
),
|
||||||
// `lockStream`'s `flush` will be invoked before `writable` fully closes,
|
state: {},
|
||||||
// but `lockStream.readable.pipeTo` will wait for `writable` to close.
|
};
|
||||||
lockStream.readable
|
},
|
||||||
.pipeTo(writable)
|
close: async () => {
|
||||||
.then(() => {
|
|
||||||
this.sendLock.notify();
|
this.sendLock.notify();
|
||||||
});
|
}
|
||||||
|
});
|
||||||
return lockStream.writable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async dispose() {
|
public override async dispose() {
|
||||||
|
|
|
@ -119,7 +119,7 @@ export class AdbSocketController extends AutoDisposable implements AdbSocketInfo
|
||||||
this.writeChunkLock.dispose();
|
this.writeChunkLock.dispose();
|
||||||
|
|
||||||
await this.dispatcher.sendPacket(AdbCommand.Close, this.localId, this.remoteId);
|
await this.dispatcher.sendPacket(AdbCommand.Close, this.localId, this.remoteId);
|
||||||
this._passthrough.writable.close();
|
this._passthroughWriter.close();
|
||||||
this.writable.close();
|
this.writable.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,7 +334,7 @@ try {
|
||||||
WritableStreamDefaultController,
|
WritableStreamDefaultController,
|
||||||
WritableStreamDefaultWriter,
|
WritableStreamDefaultWriter,
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
} = await import('stream/web'));
|
} = await import(/* webpackIgnore: true */ 'stream/web'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(Symbol.asyncIterator in ReadableStream.prototype)) {
|
if (!(Symbol.asyncIterator in ReadableStream.prototype)) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import Struct, { decodeUtf8, StructLike, StructValueType } from "@yume-chan/struct";
|
import Struct, { decodeUtf8, StructLike, StructValueType } from "@yume-chan/struct";
|
||||||
import { BufferedStream, BufferedStreamEndedError } from "../stream";
|
import { BufferedStream, BufferedStreamEndedError } from "../stream";
|
||||||
import { TransformStream } from "./stream";
|
import { chunkArrayLike } from "./chunk";
|
||||||
|
import { TransformStream, WritableStream, WritableStreamDefaultWriter } from "./stream";
|
||||||
|
|
||||||
export class DecodeUtf8Stream extends TransformStream<ArrayBuffer, string>{
|
export class DecodeUtf8Stream extends TransformStream<ArrayBuffer, string>{
|
||||||
public constructor() {
|
public constructor() {
|
||||||
|
@ -74,3 +75,51 @@ export class StructSerializeStream<T extends Struct<any, any, any, any>>
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WritableStreamHooks<T, W extends WritableStream<T>, S> {
|
||||||
|
start(): Promise<{ writable: W, state: S; }>;
|
||||||
|
close(state: S): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class HookWritableStream<T, W extends WritableStream<T>, S> extends WritableStream<T>{
|
||||||
|
public writable!: W;
|
||||||
|
|
||||||
|
private writer!: WritableStreamDefaultWriter<T>;
|
||||||
|
|
||||||
|
private state!: S;
|
||||||
|
|
||||||
|
public constructor(hooks: WritableStreamHooks<T, W, S>) {
|
||||||
|
super({
|
||||||
|
start: async () => {
|
||||||
|
const { writable, state } = await hooks.start();
|
||||||
|
this.writable = writable;
|
||||||
|
this.writer = writable.getWriter();
|
||||||
|
this.state = state;
|
||||||
|
},
|
||||||
|
write: async (chunk) => {
|
||||||
|
await this.writer.ready;
|
||||||
|
await this.writer.write(chunk);
|
||||||
|
},
|
||||||
|
abort: async (reason) => {
|
||||||
|
await this.writer.abort(reason);
|
||||||
|
hooks.close(this.state);
|
||||||
|
},
|
||||||
|
close: async () => {
|
||||||
|
await this.writer.close();
|
||||||
|
await hooks.close(this.state);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ChunkStream extends TransformStream<ArrayBuffer, ArrayBuffer>{
|
||||||
|
public constructor(size: number) {
|
||||||
|
super({
|
||||||
|
transform(chunk, controller) {
|
||||||
|
for (const piece of chunkArrayLike(chunk, size)) {
|
||||||
|
controller.enqueue(piece);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Adb, TransformStream } from "@yume-chan/adb";
|
import { Adb, AdbSync, WritableStream, WritableStreamDefaultWriter } from "@yume-chan/adb";
|
||||||
import { DEFAULT_SERVER_PATH } from "./options";
|
import { DEFAULT_SERVER_PATH } from "./options";
|
||||||
|
|
||||||
export interface PushServerOptions {
|
export interface PushServerOptions {
|
||||||
|
@ -9,21 +9,28 @@ export async function pushServerStream(
|
||||||
device: Adb,
|
device: Adb,
|
||||||
options: PushServerOptions = {}
|
options: PushServerOptions = {}
|
||||||
) {
|
) {
|
||||||
const {
|
const { path = DEFAULT_SERVER_PATH } = options;
|
||||||
path = DEFAULT_SERVER_PATH,
|
|
||||||
} = options;
|
|
||||||
|
|
||||||
const sync = await device.sync();
|
let sync!: AdbSync;
|
||||||
const writable = sync.write(path);
|
let writable!: WritableStream<ArrayBuffer>;
|
||||||
|
let writer!: WritableStreamDefaultWriter<ArrayBuffer>;
|
||||||
const lockStream = new TransformStream<ArrayBuffer, ArrayBuffer>();
|
return new WritableStream<ArrayBuffer>({
|
||||||
// Same as inside AdbSync,
|
async start() {
|
||||||
// can only use `pipeTo` to detect the writable is fully closed.
|
sync = await device.sync();
|
||||||
lockStream.readable
|
writable = sync.write(path);
|
||||||
.pipeTo(writable)
|
writer = writable.getWriter();
|
||||||
.then(() => {
|
},
|
||||||
|
async write(chunk: ArrayBuffer) {
|
||||||
|
await writer.ready;
|
||||||
|
await writer.write(chunk);
|
||||||
|
},
|
||||||
|
async abort(e) {
|
||||||
|
await writer.abort(e);
|
||||||
sync.dispose();
|
sync.dispose();
|
||||||
});
|
},
|
||||||
|
async close() {
|
||||||
return lockStream.writable;
|
await writer.close();
|
||||||
|
await sync.dispose();
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue