Commit dffea6f6 authored by Skye Yu's avatar Skye Yu

feat: get file by continue decode

parent 2c149765
import { useEffect } from 'react'; import { useEffect, useState } from 'react';
import Jensen from '..'; import Jensen from '..';
import './index.css'; import './index.css';
const jensen = new Jensen(); const jensen = new Jensen();
export function Home() { export function Home() {
const [files, setFiles] = useState<Jensen.FileInfo[]>([]);
useEffect(() => { useEffect(() => {
jensen.connect(); jensen.connect();
jensen.onconnect = () => { jensen.onconnect = () => {
console.log('connect successfully'); console.log('connect successfully');
jensen.listFiles(3).then((res) => {
console.log('files', res);
res && setFiles(res);
});
}; };
}, []); }, []);
return <button onClick={() => jensen.connect()}>Click to connect</button>; const downloadFile = () => {
const file = files[0];
console.time('---finished');
jensen.getDeviceInfo();
jensen.getFile(file.name, file.length, () => {
console.timeEnd('---finished');
});
setTimeout(() => {
jensen.getDeviceInfo();
}, 1000);
};
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px', padding: '16px', alignItems: 'center', justifyContent: 'center' }}>
<button style={{ width: '200px', height: '40px' }} onClick={() => jensen.connect()}>
Click to connect
</button>
<button style={{ width: '200px', height: '40px' }} onClick={downloadFile}>
get file
</button>
<button style={{ width: '200px', height: '40px' }} onClick={() => jensen.getDeviceInfo()}>
getDeviceInfo
</button>
</div>
);
} }
import { Logger as internalLogger, formatTime, shortcutKeys, sliceTime } from './utils'; import { Logger as internalLogger, formatTime, shortcutKeys, sliceTime, TaskQueue } from './utils';
const INVAILD = 0x00; const INVAILD = 0x00;
const QUERY_DEVICE_INFO = 0x01; const QUERY_DEVICE_INFO = 0x01;
...@@ -53,8 +53,12 @@ const COMMAND_NAMES = { ...@@ -53,8 +53,12 @@ const COMMAND_NAMES = {
[RECORD_TEST_END]: 'record test end' [RECORD_TEST_END]: 'record test end'
}; };
let Logger = null;
const taskQueue = new TaskQueue();
function Jensen(log) { function Jensen(log) {
const Logger = log || internalLogger; Logger = log || internalLogger;
let device = null; let device = null;
let actions = {}; let actions = {};
let buffer = []; let buffer = [];
...@@ -79,8 +83,14 @@ function Jensen(log) { ...@@ -79,8 +83,14 @@ function Jensen(log) {
this.onconnect = null; this.onconnect = null;
this.onreceive = null; this.onreceive = null;
this.streamingBegin = false;
const RECV_BUFF_SIZE = 51200; const RECV_BUFF_SIZE = 51200;
let worker = null;
let streamingByteView = new Uint8Array(new ArrayBuffer(RECV_BUFF_SIZE * 2));
let streamingBuffLength = 0;
const _check_conn_status = () => { const _check_conn_status = () => {
if (device?.opened === false) { if (device?.opened === false) {
try { try {
...@@ -128,6 +138,14 @@ function Jensen(log) { ...@@ -128,6 +138,14 @@ function Jensen(log) {
}; };
this.connect = async function () { this.connect = async function () {
if (window.Worker) {
worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' });
worker.onmessage = (data) => {
if (this.streamingBegin) {
taskQueue.addTask(() => continueDecode(data.data));
}
};
}
Logger.debug('jensen', 'connect', 'connect'); Logger.debug('jensen', 'connect', 'connect');
let r = await self.tryconnect(); let r = await self.tryconnect();
if (r) return; if (r) return;
...@@ -299,6 +317,7 @@ function Jensen(log) { ...@@ -299,6 +317,7 @@ function Jensen(log) {
if (device) if (device)
device.transferIn(2, RECV_BUFF_SIZE).then((r) => { device.transferIn(2, RECV_BUFF_SIZE).then((r) => {
Logger.save?.('jensen', 'tryReceive', r?.data); Logger.save?.('jensen', 'tryReceive', r?.data);
worker.postMessage(r.data);
receive(r); receive(r);
}); });
}; };
...@@ -327,6 +346,44 @@ function Jensen(log) { ...@@ -327,6 +346,44 @@ function Jensen(log) {
} }
}; };
this.resetStreamingData = () => {
streamingByteView = new ArrayBuffer(RECV_BUFF_SIZE * 2);
streamingBuffLength = 0;
this.streamingBegin = false;
};
const continueDecode = (block) => {
for (let k = 0; k < block.byteLength; k++) {
streamingByteView[k + streamingBuffLength] = block.getInt8(k);
}
streamingBuffLength += block.byteLength;
let rst = null;
let _startIndex = 0;
while (true) {
try {
rst = decodeMessage(streamingByteView, _startIndex, streamingBuffLength);
} catch (e) {
let msgid = parseInt(current.replace(/^cmd-(\d+)-(\d+)$/gi, '$1'));
let handler = Jensen.handlers[msgid];
handler(null, self);
trigger(null, msgid);
break;
}
if (rst == null) {
break;
}
const handler = Jensen.handlers[rst.message.id];
const r = handler(rst.message, self);
r && trigger(r, rst.message.id);
_startIndex += rst.length;
}
for (let k = 0, bs = streamingBuffLength - _startIndex; k < bs; k++) {
streamingByteView[k] = streamingByteView[k + _startIndex];
}
streamingBuffLength = streamingBuffLength - _startIndex;
return 'finished';
};
const tryDecode = function () { const tryDecode = function () {
// 一个容器,比单独任意一个小包要大一点儿,好像还差一点儿 // 一个容器,比单独任意一个小包要大一点儿,好像还差一点儿
let stime = new Date(); let stime = new Date();
...@@ -410,7 +467,10 @@ function Jensen(log) { ...@@ -410,7 +467,10 @@ function Jensen(log) {
const decodeMessage = function (dataView, startIndex, buffLength) { const decodeMessage = function (dataView, startIndex, buffLength) {
let dataLen = buffLength - startIndex; let dataLen = buffLength - startIndex;
if (dataLen < 12) return null; if (dataLen < 12) return null;
if (dataView[startIndex + 0] !== 0x12 || dataView[startIndex + 1] !== 0x34) throw new Error('invalid header'); if (dataView[startIndex + 0] !== 0x12 || dataView[startIndex + 1] !== 0x34) {
console.log('0000000000000000000000', dataView);
throw new Error('invalid header');
}
// 2 字节的指令id // 2 字节的指令id
let idx = 2; let idx = 2;
// let cmdid = this.nextShort(idx); // let cmdid = this.nextShort(idx);
...@@ -435,7 +495,10 @@ function Jensen(log) { ...@@ -435,7 +495,10 @@ function Jensen(log) {
// 需要去除的字节数 // 需要去除的字节数
var cutLen = 0; var cutLen = 0;
// 数据还没有完全准备好 // 数据还没有完全准备好
if (dataLen < 12 + len + padding) return null; if (dataLen < 12 + len + padding) {
console.log(dataLen, len, padding);
return null;
}
// 去掉header部分 // 去掉header部分
// 下面这一行做什么用的? // 下面这一行做什么用的?
// for (let i = 0; i < 12; i++) this.buffer[i + cutLen]; // for (let i = 0; i < 12; i++) this.buffer[i + cutLen];
...@@ -777,6 +840,7 @@ Jensen.prototype.getFile = async function (filename, length, ondata, onprogress) ...@@ -777,6 +840,7 @@ Jensen.prototype.getFile = async function (filename, length, ondata, onprogress)
ondata(msg.body); ondata(msg.body);
Logger.info('jensen', 'getFile length', `${length} ${flen}`); Logger.info('jensen', 'getFile length', `${length} ${flen}`);
if (flen >= length) { if (flen >= length) {
this.resetStreamingData();
document.removeEventListener('visibilitychange', visibilitychange); document.removeEventListener('visibilitychange', visibilitychange);
Logger.info('jensen', 'getFile', 'file download finish.'); Logger.info('jensen', 'getFile', 'file download finish.');
clearEventAndTask(); clearEventAndTask();
...@@ -784,12 +848,14 @@ Jensen.prototype.getFile = async function (filename, length, ondata, onprogress) ...@@ -784,12 +848,14 @@ Jensen.prototype.getFile = async function (filename, length, ondata, onprogress)
return 'OK'; return 'OK';
} }
} else { } else {
this.resetStreamingData();
document.removeEventListener('visibilitychange', visibilitychange); document.removeEventListener('visibilitychange', visibilitychange);
clearEventAndTask(); clearEventAndTask();
Logger.info('jensen', 'getFile', 'file download fail.'); Logger.info('jensen', 'getFile', 'file download fail.');
ondata('fail'); ondata('fail');
} }
}; };
this.streamingBegin = true;
this.onreceive = onprogress; this.onreceive = onprogress;
Jensen.registerHandler(TRANSFER_FILE, handler); Jensen.registerHandler(TRANSFER_FILE, handler);
this.send(new Command(TRANSFER_FILE).body(fname)); this.send(new Command(TRANSFER_FILE).body(fname));
...@@ -870,6 +936,7 @@ Jensen.prototype.getRecordingFile = function (seconds) { ...@@ -870,6 +936,7 @@ Jensen.prototype.getRecordingFile = function (seconds) {
Jensen.prototype.recordTestStart = async function (type, seconds) { Jensen.prototype.recordTestStart = async function (type, seconds) {
return this.send(new Command(0xf008).body([type]), seconds); return this.send(new Command(0xf008).body([type]), seconds);
}; };
Jensen.prototype.recordTestEnd = async function (type, seconds) { Jensen.prototype.recordTestEnd = async function (type, seconds) {
return this.send(new Command(0xf009).body([type]), seconds); return this.send(new Command(0xf009).body([type]), seconds);
}; };
......
...@@ -308,3 +308,13 @@ export const shortcutKeys = { ...@@ -308,3 +308,13 @@ export const shortcutKeys = {
Linux: [enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes] Linux: [enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes]
} }
}; };
export class TaskQueue {
constructor() {
this.queue = Promise.resolve();
}
addTask(task) {
this.queue = this.queue.then(() => task());
}
}
// worker.js
self.onmessage = function (event) {
self.postMessage(event.data);
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment