@midscene/playground-app 1.6.3 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/PlaygroundApp.mjs +53 -8
- package/dist/es/ScrcpyPanel.mjs +3 -50
- package/dist/es/scrcpy-stream.mjs +53 -0
- package/dist/es/session-setup.mjs +13 -0
- package/dist/es/useServerStatus.mjs +55 -44
- package/dist/lib/PlaygroundApp.js +53 -8
- package/dist/lib/ScrcpyPanel.js +3 -50
- package/dist/lib/scrcpy-stream.js +87 -0
- package/dist/lib/session-setup.js +47 -0
- package/dist/lib/useServerStatus.js +54 -43
- package/dist/types/scrcpy-stream.d.ts +16 -0
- package/dist/types/session-setup.d.ts +2 -0
- package/dist/types/useServerStatus.d.ts +1 -0
- package/package.json +8 -5
|
@@ -8,6 +8,7 @@ import { PreviewRenderer } from "./PreviewRenderer.mjs";
|
|
|
8
8
|
import { SessionSetupPanel } from "./SessionSetupPanel.mjs";
|
|
9
9
|
import server_offline_background from "./icons/server-offline-background.mjs";
|
|
10
10
|
import server_offline_foreground from "./icons/server-offline-foreground.mjs";
|
|
11
|
+
import { resolveAutoCreateSessionInput } from "./session-setup.mjs";
|
|
11
12
|
import { buildSessionInitialValues, resolveSessionViewState } from "./session-state.mjs";
|
|
12
13
|
import { useServerStatus } from "./useServerStatus.mjs";
|
|
13
14
|
import "./PlaygroundApp.css";
|
|
@@ -106,7 +107,7 @@ function PlaygroundApp({ serverUrl, appVersion, title = 'Playground', defaultDev
|
|
|
106
107
|
}), [
|
|
107
108
|
serverUrl
|
|
108
109
|
]);
|
|
109
|
-
const { serverOnline, isUserOperating, deviceType, runtimeInfo, executionUxHints } = useServerStatus(playgroundSDK, defaultDeviceType, pollIntervalMs);
|
|
110
|
+
const { serverOnline, isUserOperating, deviceType, runtimeInfo, executionUxHints, refreshServerState } = useServerStatus(playgroundSDK, defaultDeviceType, pollIntervalMs);
|
|
110
111
|
const sessionViewState = useMemo(()=>resolveSessionViewState(runtimeInfo), [
|
|
111
112
|
runtimeInfo
|
|
112
113
|
]);
|
|
@@ -114,6 +115,8 @@ function PlaygroundApp({ serverUrl, appVersion, title = 'Playground', defaultDev
|
|
|
114
115
|
const countdownResolveRef = useRef(null);
|
|
115
116
|
const mountedRef = useRef(true);
|
|
116
117
|
const lastSetupPlatformIdRef = useRef(void 0);
|
|
118
|
+
const autoCreateSignatureRef = useRef(null);
|
|
119
|
+
const autoCreateDisabledRef = useRef(false);
|
|
117
120
|
const finishCountdown = useCallback(()=>{
|
|
118
121
|
if (null !== countdownTimerRef.current) {
|
|
119
122
|
window.clearInterval(countdownTimerRef.current);
|
|
@@ -242,31 +245,41 @@ function PlaygroundApp({ serverUrl, appVersion, title = 'Playground', defaultDev
|
|
|
242
245
|
version: appVersion,
|
|
243
246
|
targetName: null != (_ref1 = null != (_ref = null != (_runtimeInfo_platformId = null == runtimeInfo ? void 0 : runtimeInfo.platformId) ? _runtimeInfo_platformId : null == branding ? void 0 : branding.targetName) ? _ref : deviceType) ? _ref1 : 'screen'
|
|
244
247
|
});
|
|
245
|
-
const
|
|
248
|
+
const createSession = useCallback((input, options)=>_async_to_generator(function*() {
|
|
246
249
|
try {
|
|
247
|
-
const values = yield setupForm.validateFields();
|
|
250
|
+
const values = null != input ? input : yield setupForm.validateFields();
|
|
248
251
|
setSessionMutating(true);
|
|
249
252
|
yield playgroundSDK.createSession(values);
|
|
250
|
-
messageApi.success('Agent created');
|
|
251
|
-
yield
|
|
253
|
+
if (!(null == options ? void 0 : options.silent)) messageApi.success('Agent created');
|
|
254
|
+
yield refreshServerState();
|
|
255
|
+
return true;
|
|
252
256
|
} catch (error) {
|
|
253
|
-
if (error.errorFields) return;
|
|
257
|
+
if (error.errorFields) return false;
|
|
254
258
|
const errorMessage = error instanceof Error ? error.message : 'Failed to create Agent';
|
|
255
259
|
messageApi.error(errorMessage);
|
|
260
|
+
return false;
|
|
256
261
|
} finally{
|
|
257
262
|
setSessionMutating(false);
|
|
258
263
|
}
|
|
259
264
|
})(), [
|
|
260
265
|
messageApi,
|
|
261
266
|
playgroundSDK,
|
|
262
|
-
|
|
267
|
+
refreshServerState,
|
|
263
268
|
setupForm
|
|
264
269
|
]);
|
|
270
|
+
const handleCreateSession = useCallback(()=>_async_to_generator(function*() {
|
|
271
|
+
autoCreateDisabledRef.current = true;
|
|
272
|
+
yield createSession();
|
|
273
|
+
})(), [
|
|
274
|
+
createSession
|
|
275
|
+
]);
|
|
265
276
|
const handleDestroySession = useCallback(()=>_async_to_generator(function*() {
|
|
266
277
|
try {
|
|
278
|
+
autoCreateDisabledRef.current = true;
|
|
267
279
|
setSessionMutating(true);
|
|
268
280
|
yield playgroundSDK.destroySession();
|
|
269
281
|
messageApi.success('Session disconnected');
|
|
282
|
+
yield refreshServerState();
|
|
270
283
|
yield refreshSessionSetup();
|
|
271
284
|
} catch (error) {
|
|
272
285
|
const errorMessage = error instanceof Error ? error.message : 'Failed to disconnect session';
|
|
@@ -277,8 +290,39 @@ function PlaygroundApp({ serverUrl, appVersion, title = 'Playground', defaultDev
|
|
|
277
290
|
})(), [
|
|
278
291
|
messageApi,
|
|
279
292
|
playgroundSDK,
|
|
293
|
+
refreshServerState,
|
|
280
294
|
refreshSessionSetup
|
|
281
295
|
]);
|
|
296
|
+
useEffect(()=>{
|
|
297
|
+
if (sessionViewState.connected) {
|
|
298
|
+
autoCreateSignatureRef.current = null;
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (!serverOnline || sessionLoading || sessionMutating || sessionSetupError || autoCreateDisabledRef.current) return;
|
|
302
|
+
const autoCreateInput = resolveAutoCreateSessionInput(sessionSetup, setupForm.getFieldsValue(true));
|
|
303
|
+
if (!autoCreateInput) {
|
|
304
|
+
autoCreateSignatureRef.current = null;
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const signature = JSON.stringify(autoCreateInput);
|
|
308
|
+
if (autoCreateSignatureRef.current === signature) return;
|
|
309
|
+
autoCreateSignatureRef.current = signature;
|
|
310
|
+
(()=>_async_to_generator(function*() {
|
|
311
|
+
const created = yield createSession(autoCreateInput, {
|
|
312
|
+
silent: true
|
|
313
|
+
});
|
|
314
|
+
if (!created) autoCreateSignatureRef.current = null;
|
|
315
|
+
})())();
|
|
316
|
+
}, [
|
|
317
|
+
createSession,
|
|
318
|
+
serverOnline,
|
|
319
|
+
sessionLoading,
|
|
320
|
+
sessionMutating,
|
|
321
|
+
sessionSetup,
|
|
322
|
+
sessionSetupError,
|
|
323
|
+
sessionViewState.connected,
|
|
324
|
+
setupForm
|
|
325
|
+
]);
|
|
282
326
|
if (!serverOnline) return /*#__PURE__*/ jsx(ConfigProvider, {
|
|
283
327
|
theme: globalThemeConfig(),
|
|
284
328
|
children: /*#__PURE__*/ jsx("div", {
|
|
@@ -400,7 +444,8 @@ function PlaygroundApp({ serverUrl, appVersion, title = 'Playground', defaultDev
|
|
|
400
444
|
/*#__PURE__*/ jsx(Logo, {}),
|
|
401
445
|
/*#__PURE__*/ jsx(NavActions, {
|
|
402
446
|
showTooltipWhenEmpty: false,
|
|
403
|
-
showModelName: false
|
|
447
|
+
showModelName: false,
|
|
448
|
+
playgroundSDK: playgroundSDK
|
|
404
449
|
})
|
|
405
450
|
]
|
|
406
451
|
})
|
package/dist/es/ScrcpyPanel.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import { BitmapVideoFrameRenderer, WebCodecsVideoDecoder, WebGLVideoFrameRendere
|
|
|
4
4
|
import { Alert, Button, Card, Space, Spin, Typography } from "antd";
|
|
5
5
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
6
6
|
import { io } from "socket.io-client";
|
|
7
|
+
import { createScrcpyVideoStream } from "./scrcpy-stream.mjs";
|
|
7
8
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
8
9
|
try {
|
|
9
10
|
var info = gen[key](arg);
|
|
@@ -131,55 +132,6 @@ function ScrcpyPanel({ serverUrl, reconnectInterval = 3000 }) {
|
|
|
131
132
|
});
|
|
132
133
|
return decoder;
|
|
133
134
|
})();
|
|
134
|
-
const setupVideoStream = ()=>{
|
|
135
|
-
const socket = socketRef.current;
|
|
136
|
-
let configurationPacketSent = false;
|
|
137
|
-
let pendingDataPackets = [];
|
|
138
|
-
const transformStream = new TransformStream({
|
|
139
|
-
transform (chunk, controller) {
|
|
140
|
-
const packet = {
|
|
141
|
-
type: chunk.type,
|
|
142
|
-
data: new Uint8Array(chunk.data),
|
|
143
|
-
timestamp: chunk.timestamp
|
|
144
|
-
};
|
|
145
|
-
if ('configuration' === packet.type) {
|
|
146
|
-
configurationPacketSent = true;
|
|
147
|
-
controller.enqueue(packet);
|
|
148
|
-
pendingDataPackets.forEach((queuedPacket)=>controller.enqueue(queuedPacket));
|
|
149
|
-
pendingDataPackets = [];
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
if ('data' === packet.type && !configurationPacketSent) return void pendingDataPackets.push(packet);
|
|
153
|
-
controller.enqueue(packet);
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
let cleanupListeners;
|
|
157
|
-
const readable = new ReadableStream({
|
|
158
|
-
start (controller) {
|
|
159
|
-
const handleVideoData = (data)=>{
|
|
160
|
-
try {
|
|
161
|
-
controller.enqueue(data);
|
|
162
|
-
} catch (error) {
|
|
163
|
-
controller.error(error);
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
const handleDisconnect = ()=>controller.close();
|
|
167
|
-
const handleError = (error)=>controller.error(error);
|
|
168
|
-
cleanupListeners = ()=>{
|
|
169
|
-
null == socket || socket.off('video-data', handleVideoData);
|
|
170
|
-
null == socket || socket.off('disconnect', handleDisconnect);
|
|
171
|
-
null == socket || socket.off('error', handleError);
|
|
172
|
-
};
|
|
173
|
-
null == socket || socket.on('video-data', handleVideoData);
|
|
174
|
-
null == socket || socket.on('disconnect', handleDisconnect);
|
|
175
|
-
null == socket || socket.on('error', handleError);
|
|
176
|
-
},
|
|
177
|
-
cancel () {
|
|
178
|
-
null == cleanupListeners || cleanupListeners();
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
return readable.pipeThrough(transformStream);
|
|
182
|
-
};
|
|
183
135
|
const connect = ()=>{
|
|
184
136
|
if (disposed) return;
|
|
185
137
|
manuallyDisconnectedRef.current = false;
|
|
@@ -192,6 +144,7 @@ function ScrcpyPanel({ serverUrl, reconnectInterval = 3000 }) {
|
|
|
192
144
|
timeout: 10000
|
|
193
145
|
});
|
|
194
146
|
socketRef.current = socket;
|
|
147
|
+
const videoStream = createScrcpyVideoStream(socket);
|
|
195
148
|
socket.on('connect', ()=>{
|
|
196
149
|
socket.emit('connect-device', {
|
|
197
150
|
maxSize: 1024
|
|
@@ -207,7 +160,7 @@ function ScrcpyPanel({ serverUrl, reconnectInterval = 3000 }) {
|
|
|
207
160
|
width: metadata.width,
|
|
208
161
|
height: metadata.height
|
|
209
162
|
});
|
|
210
|
-
|
|
163
|
+
videoStream.pipeTo(decoder.writable).catch((error)=>{
|
|
211
164
|
if (disposed) return;
|
|
212
165
|
setStatus('error');
|
|
213
166
|
setErrorMessage(error.message);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
function createScrcpyVideoStream(socket) {
|
|
2
|
+
let configurationPacketSent = false;
|
|
3
|
+
let pendingDataPackets = [];
|
|
4
|
+
const transformStream = new TransformStream({
|
|
5
|
+
transform (chunk, controller) {
|
|
6
|
+
if ('configuration' === chunk.type) {
|
|
7
|
+
configurationPacketSent = true;
|
|
8
|
+
controller.enqueue(chunk);
|
|
9
|
+
pendingDataPackets.forEach((queuedPacket)=>controller.enqueue(queuedPacket));
|
|
10
|
+
pendingDataPackets = [];
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if ('data' === chunk.type && !configurationPacketSent) return void pendingDataPackets.push(chunk);
|
|
14
|
+
controller.enqueue(chunk);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
let cleanupListeners;
|
|
18
|
+
const readable = new ReadableStream({
|
|
19
|
+
start (controller) {
|
|
20
|
+
const handleVideoData = (data)=>{
|
|
21
|
+
try {
|
|
22
|
+
const payload = new Uint8Array(data.data);
|
|
23
|
+
if ('configuration' === data.type) return void controller.enqueue({
|
|
24
|
+
type: 'configuration',
|
|
25
|
+
data: payload
|
|
26
|
+
});
|
|
27
|
+
controller.enqueue({
|
|
28
|
+
type: 'data',
|
|
29
|
+
data: payload,
|
|
30
|
+
keyframe: data.keyFrame
|
|
31
|
+
});
|
|
32
|
+
} catch (error) {
|
|
33
|
+
controller.error(error);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const handleDisconnect = ()=>controller.close();
|
|
37
|
+
const handleError = (error)=>controller.error(error);
|
|
38
|
+
cleanupListeners = ()=>{
|
|
39
|
+
socket.off('video-data', handleVideoData);
|
|
40
|
+
socket.off('disconnect', handleDisconnect);
|
|
41
|
+
socket.off('error', handleError);
|
|
42
|
+
};
|
|
43
|
+
socket.on('video-data', handleVideoData);
|
|
44
|
+
socket.on('disconnect', handleDisconnect);
|
|
45
|
+
socket.on('error', handleError);
|
|
46
|
+
},
|
|
47
|
+
cancel () {
|
|
48
|
+
null == cleanupListeners || cleanupListeners();
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return readable.pipeThrough(transformStream);
|
|
52
|
+
}
|
|
53
|
+
export { createScrcpyVideoStream };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { buildSessionInitialValues } from "./session-state.mjs";
|
|
2
|
+
function hasSessionFieldValue(value) {
|
|
3
|
+
return null != value && '' !== value;
|
|
4
|
+
}
|
|
5
|
+
function resolveAutoCreateSessionInput(setup, existingValues = {}) {
|
|
6
|
+
if (!(null == setup ? void 0 : setup.autoSubmitWhenReady)) return null;
|
|
7
|
+
const values = buildSessionInitialValues(setup, existingValues);
|
|
8
|
+
for (const field of setup.fields)if (field.required) {
|
|
9
|
+
if (!hasSessionFieldValue(values[field.key])) return null;
|
|
10
|
+
}
|
|
11
|
+
return values;
|
|
12
|
+
}
|
|
13
|
+
export { resolveAutoCreateSessionInput };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useRef, useState } from "react";
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
2
|
import { buildFallbackRuntimeInfo, filterValidExecutionUxHints, normalizeRuntimeDeviceType } from "./runtime-info.mjs";
|
|
3
3
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
4
4
|
try {
|
|
@@ -33,6 +33,13 @@ function useServerStatus(playgroundSDK, defaultDeviceType, pollIntervalMs) {
|
|
|
33
33
|
const [runtimeInfo, setRuntimeInfo] = useState(null);
|
|
34
34
|
const [executionUxHints, setExecutionUxHints] = useState([]);
|
|
35
35
|
const runtimeInfoRef = useRef(null);
|
|
36
|
+
const mountedRef = useRef(true);
|
|
37
|
+
useEffect(()=>{
|
|
38
|
+
mountedRef.current = true;
|
|
39
|
+
return ()=>{
|
|
40
|
+
mountedRef.current = false;
|
|
41
|
+
};
|
|
42
|
+
}, []);
|
|
36
43
|
useEffect(()=>{
|
|
37
44
|
runtimeInfoRef.current = runtimeInfo;
|
|
38
45
|
}, [
|
|
@@ -45,65 +52,69 @@ function useServerStatus(playgroundSDK, defaultDeviceType, pollIntervalMs) {
|
|
|
45
52
|
}, [
|
|
46
53
|
playgroundSDK
|
|
47
54
|
]);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
const refreshServerState = useCallback(()=>_async_to_generator(function*() {
|
|
56
|
+
try {
|
|
57
|
+
const online = yield playgroundSDK.checkStatus();
|
|
58
|
+
if (!mountedRef.current) return;
|
|
59
|
+
setServerOnline(online);
|
|
60
|
+
if (!online) {
|
|
61
|
+
runtimeInfoRef.current = null;
|
|
62
|
+
setRuntimeInfo(null);
|
|
63
|
+
setExecutionUxHints([]);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
51
66
|
try {
|
|
52
|
-
const
|
|
53
|
-
if (!
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
setExecutionUxHints(
|
|
67
|
+
const nextRuntimeInfo = yield playgroundSDK.getRuntimeInfo();
|
|
68
|
+
if (!mountedRef.current) return;
|
|
69
|
+
if (nextRuntimeInfo) {
|
|
70
|
+
runtimeInfoRef.current = nextRuntimeInfo;
|
|
71
|
+
setRuntimeInfo(nextRuntimeInfo);
|
|
72
|
+
setDeviceType(normalizeRuntimeDeviceType(nextRuntimeInfo, defaultDeviceType));
|
|
73
|
+
setExecutionUxHints(filterValidExecutionUxHints(nextRuntimeInfo));
|
|
59
74
|
return;
|
|
60
75
|
}
|
|
61
|
-
try {
|
|
62
|
-
const nextRuntimeInfo = yield playgroundSDK.getRuntimeInfo();
|
|
63
|
-
if (!active) return;
|
|
64
|
-
if (nextRuntimeInfo) {
|
|
65
|
-
setRuntimeInfo(nextRuntimeInfo);
|
|
66
|
-
setDeviceType(normalizeRuntimeDeviceType(nextRuntimeInfo, defaultDeviceType));
|
|
67
|
-
setExecutionUxHints(filterValidExecutionUxHints(nextRuntimeInfo));
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
} catch (error) {
|
|
71
|
-
console.warn('Failed to get runtime info:', error);
|
|
72
|
-
}
|
|
73
|
-
try {
|
|
74
|
-
const interfaceInfo = yield playgroundSDK.getInterfaceInfo();
|
|
75
|
-
if (!active || !(null == interfaceInfo ? void 0 : interfaceInfo.type)) return;
|
|
76
|
-
const fallbackRuntimeInfo = buildFallbackRuntimeInfo(runtimeInfoRef.current, interfaceInfo);
|
|
77
|
-
runtimeInfoRef.current = fallbackRuntimeInfo;
|
|
78
|
-
setRuntimeInfo(fallbackRuntimeInfo);
|
|
79
|
-
setDeviceType(normalizeRuntimeDeviceType(fallbackRuntimeInfo, defaultDeviceType));
|
|
80
|
-
setExecutionUxHints(filterValidExecutionUxHints(fallbackRuntimeInfo));
|
|
81
|
-
} catch (error) {
|
|
82
|
-
console.warn('Failed to get interface info:', error);
|
|
83
|
-
}
|
|
84
76
|
} catch (error) {
|
|
85
|
-
|
|
86
|
-
console.error('Failed to check server status:', error);
|
|
87
|
-
setServerOnline(false);
|
|
77
|
+
console.warn('Failed to get runtime info:', error);
|
|
88
78
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
79
|
+
try {
|
|
80
|
+
const interfaceInfo = yield playgroundSDK.getInterfaceInfo();
|
|
81
|
+
if (!mountedRef.current || !(null == interfaceInfo ? void 0 : interfaceInfo.type)) return;
|
|
82
|
+
const fallbackRuntimeInfo = buildFallbackRuntimeInfo(runtimeInfoRef.current, interfaceInfo);
|
|
83
|
+
runtimeInfoRef.current = fallbackRuntimeInfo;
|
|
84
|
+
setRuntimeInfo(fallbackRuntimeInfo);
|
|
85
|
+
setDeviceType(normalizeRuntimeDeviceType(fallbackRuntimeInfo, defaultDeviceType));
|
|
86
|
+
setExecutionUxHints(filterValidExecutionUxHints(fallbackRuntimeInfo));
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.warn('Failed to get interface info:', error);
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (!mountedRef.current) return;
|
|
92
|
+
console.error('Failed to check server status:', error);
|
|
93
|
+
setServerOnline(false);
|
|
94
|
+
}
|
|
95
|
+
})(), [
|
|
96
|
+
defaultDeviceType,
|
|
97
|
+
playgroundSDK
|
|
98
|
+
]);
|
|
99
|
+
useEffect(()=>{
|
|
100
|
+
refreshServerState();
|
|
101
|
+
const interval = window.setInterval(()=>{
|
|
102
|
+
refreshServerState();
|
|
103
|
+
}, pollIntervalMs);
|
|
92
104
|
return ()=>{
|
|
93
|
-
active = false;
|
|
94
105
|
window.clearInterval(interval);
|
|
95
106
|
};
|
|
96
107
|
}, [
|
|
97
|
-
playgroundSDK,
|
|
98
108
|
pollIntervalMs,
|
|
99
|
-
|
|
109
|
+
refreshServerState
|
|
100
110
|
]);
|
|
101
111
|
return {
|
|
102
112
|
serverOnline,
|
|
103
113
|
isUserOperating,
|
|
104
114
|
deviceType,
|
|
105
115
|
runtimeInfo,
|
|
106
|
-
executionUxHints
|
|
116
|
+
executionUxHints,
|
|
117
|
+
refreshServerState
|
|
107
118
|
};
|
|
108
119
|
}
|
|
109
120
|
export { useServerStatus };
|
|
@@ -47,6 +47,7 @@ const server_offline_background_js_namespaceObject = require("./icons/server-off
|
|
|
47
47
|
var server_offline_background_js_default = /*#__PURE__*/ __webpack_require__.n(server_offline_background_js_namespaceObject);
|
|
48
48
|
const server_offline_foreground_js_namespaceObject = require("./icons/server-offline-foreground.js");
|
|
49
49
|
var server_offline_foreground_js_default = /*#__PURE__*/ __webpack_require__.n(server_offline_foreground_js_namespaceObject);
|
|
50
|
+
const external_session_setup_js_namespaceObject = require("./session-setup.js");
|
|
50
51
|
const external_session_state_js_namespaceObject = require("./session-state.js");
|
|
51
52
|
const external_useServerStatus_js_namespaceObject = require("./useServerStatus.js");
|
|
52
53
|
require("./PlaygroundApp.css");
|
|
@@ -145,7 +146,7 @@ function PlaygroundApp({ serverUrl, appVersion, title = 'Playground', defaultDev
|
|
|
145
146
|
}), [
|
|
146
147
|
serverUrl
|
|
147
148
|
]);
|
|
148
|
-
const { serverOnline, isUserOperating, deviceType, runtimeInfo, executionUxHints } = (0, external_useServerStatus_js_namespaceObject.useServerStatus)(playgroundSDK, defaultDeviceType, pollIntervalMs);
|
|
149
|
+
const { serverOnline, isUserOperating, deviceType, runtimeInfo, executionUxHints, refreshServerState } = (0, external_useServerStatus_js_namespaceObject.useServerStatus)(playgroundSDK, defaultDeviceType, pollIntervalMs);
|
|
149
150
|
const sessionViewState = (0, external_react_namespaceObject.useMemo)(()=>(0, external_session_state_js_namespaceObject.resolveSessionViewState)(runtimeInfo), [
|
|
150
151
|
runtimeInfo
|
|
151
152
|
]);
|
|
@@ -153,6 +154,8 @@ function PlaygroundApp({ serverUrl, appVersion, title = 'Playground', defaultDev
|
|
|
153
154
|
const countdownResolveRef = (0, external_react_namespaceObject.useRef)(null);
|
|
154
155
|
const mountedRef = (0, external_react_namespaceObject.useRef)(true);
|
|
155
156
|
const lastSetupPlatformIdRef = (0, external_react_namespaceObject.useRef)(void 0);
|
|
157
|
+
const autoCreateSignatureRef = (0, external_react_namespaceObject.useRef)(null);
|
|
158
|
+
const autoCreateDisabledRef = (0, external_react_namespaceObject.useRef)(false);
|
|
156
159
|
const finishCountdown = (0, external_react_namespaceObject.useCallback)(()=>{
|
|
157
160
|
if (null !== countdownTimerRef.current) {
|
|
158
161
|
window.clearInterval(countdownTimerRef.current);
|
|
@@ -281,31 +284,41 @@ function PlaygroundApp({ serverUrl, appVersion, title = 'Playground', defaultDev
|
|
|
281
284
|
version: appVersion,
|
|
282
285
|
targetName: null != (_ref1 = null != (_ref = null != (_runtimeInfo_platformId = null == runtimeInfo ? void 0 : runtimeInfo.platformId) ? _runtimeInfo_platformId : null == branding ? void 0 : branding.targetName) ? _ref : deviceType) ? _ref1 : 'screen'
|
|
283
286
|
});
|
|
284
|
-
const
|
|
287
|
+
const createSession = (0, external_react_namespaceObject.useCallback)((input, options)=>_async_to_generator(function*() {
|
|
285
288
|
try {
|
|
286
|
-
const values = yield setupForm.validateFields();
|
|
289
|
+
const values = null != input ? input : yield setupForm.validateFields();
|
|
287
290
|
setSessionMutating(true);
|
|
288
291
|
yield playgroundSDK.createSession(values);
|
|
289
|
-
messageApi.success('Agent created');
|
|
290
|
-
yield
|
|
292
|
+
if (!(null == options ? void 0 : options.silent)) messageApi.success('Agent created');
|
|
293
|
+
yield refreshServerState();
|
|
294
|
+
return true;
|
|
291
295
|
} catch (error) {
|
|
292
|
-
if (error.errorFields) return;
|
|
296
|
+
if (error.errorFields) return false;
|
|
293
297
|
const errorMessage = error instanceof Error ? error.message : 'Failed to create Agent';
|
|
294
298
|
messageApi.error(errorMessage);
|
|
299
|
+
return false;
|
|
295
300
|
} finally{
|
|
296
301
|
setSessionMutating(false);
|
|
297
302
|
}
|
|
298
303
|
})(), [
|
|
299
304
|
messageApi,
|
|
300
305
|
playgroundSDK,
|
|
301
|
-
|
|
306
|
+
refreshServerState,
|
|
302
307
|
setupForm
|
|
303
308
|
]);
|
|
309
|
+
const handleCreateSession = (0, external_react_namespaceObject.useCallback)(()=>_async_to_generator(function*() {
|
|
310
|
+
autoCreateDisabledRef.current = true;
|
|
311
|
+
yield createSession();
|
|
312
|
+
})(), [
|
|
313
|
+
createSession
|
|
314
|
+
]);
|
|
304
315
|
const handleDestroySession = (0, external_react_namespaceObject.useCallback)(()=>_async_to_generator(function*() {
|
|
305
316
|
try {
|
|
317
|
+
autoCreateDisabledRef.current = true;
|
|
306
318
|
setSessionMutating(true);
|
|
307
319
|
yield playgroundSDK.destroySession();
|
|
308
320
|
messageApi.success('Session disconnected');
|
|
321
|
+
yield refreshServerState();
|
|
309
322
|
yield refreshSessionSetup();
|
|
310
323
|
} catch (error) {
|
|
311
324
|
const errorMessage = error instanceof Error ? error.message : 'Failed to disconnect session';
|
|
@@ -316,8 +329,39 @@ function PlaygroundApp({ serverUrl, appVersion, title = 'Playground', defaultDev
|
|
|
316
329
|
})(), [
|
|
317
330
|
messageApi,
|
|
318
331
|
playgroundSDK,
|
|
332
|
+
refreshServerState,
|
|
319
333
|
refreshSessionSetup
|
|
320
334
|
]);
|
|
335
|
+
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
336
|
+
if (sessionViewState.connected) {
|
|
337
|
+
autoCreateSignatureRef.current = null;
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (!serverOnline || sessionLoading || sessionMutating || sessionSetupError || autoCreateDisabledRef.current) return;
|
|
341
|
+
const autoCreateInput = (0, external_session_setup_js_namespaceObject.resolveAutoCreateSessionInput)(sessionSetup, setupForm.getFieldsValue(true));
|
|
342
|
+
if (!autoCreateInput) {
|
|
343
|
+
autoCreateSignatureRef.current = null;
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const signature = JSON.stringify(autoCreateInput);
|
|
347
|
+
if (autoCreateSignatureRef.current === signature) return;
|
|
348
|
+
autoCreateSignatureRef.current = signature;
|
|
349
|
+
(()=>_async_to_generator(function*() {
|
|
350
|
+
const created = yield createSession(autoCreateInput, {
|
|
351
|
+
silent: true
|
|
352
|
+
});
|
|
353
|
+
if (!created) autoCreateSignatureRef.current = null;
|
|
354
|
+
})())();
|
|
355
|
+
}, [
|
|
356
|
+
createSession,
|
|
357
|
+
serverOnline,
|
|
358
|
+
sessionLoading,
|
|
359
|
+
sessionMutating,
|
|
360
|
+
sessionSetup,
|
|
361
|
+
sessionSetupError,
|
|
362
|
+
sessionViewState.connected,
|
|
363
|
+
setupForm
|
|
364
|
+
]);
|
|
321
365
|
if (!serverOnline) return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_antd_namespaceObject.ConfigProvider, {
|
|
322
366
|
theme: (0, visualizer_namespaceObject.globalThemeConfig)(),
|
|
323
367
|
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
|
|
@@ -439,7 +483,8 @@ function PlaygroundApp({ serverUrl, appVersion, title = 'Playground', defaultDev
|
|
|
439
483
|
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(visualizer_namespaceObject.Logo, {}),
|
|
440
484
|
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(visualizer_namespaceObject.NavActions, {
|
|
441
485
|
showTooltipWhenEmpty: false,
|
|
442
|
-
showModelName: false
|
|
486
|
+
showModelName: false,
|
|
487
|
+
playgroundSDK: playgroundSDK
|
|
443
488
|
})
|
|
444
489
|
]
|
|
445
490
|
})
|
package/dist/lib/ScrcpyPanel.js
CHANGED
|
@@ -32,6 +32,7 @@ const scrcpy_decoder_webcodecs_namespaceObject = require("@yume-chan/scrcpy-deco
|
|
|
32
32
|
const external_antd_namespaceObject = require("antd");
|
|
33
33
|
const external_react_namespaceObject = require("react");
|
|
34
34
|
const external_socket_io_client_namespaceObject = require("socket.io-client");
|
|
35
|
+
const external_scrcpy_stream_js_namespaceObject = require("./scrcpy-stream.js");
|
|
35
36
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
36
37
|
try {
|
|
37
38
|
var info = gen[key](arg);
|
|
@@ -159,55 +160,6 @@ function ScrcpyPanel({ serverUrl, reconnectInterval = 3000 }) {
|
|
|
159
160
|
});
|
|
160
161
|
return decoder;
|
|
161
162
|
})();
|
|
162
|
-
const setupVideoStream = ()=>{
|
|
163
|
-
const socket = socketRef.current;
|
|
164
|
-
let configurationPacketSent = false;
|
|
165
|
-
let pendingDataPackets = [];
|
|
166
|
-
const transformStream = new TransformStream({
|
|
167
|
-
transform (chunk, controller) {
|
|
168
|
-
const packet = {
|
|
169
|
-
type: chunk.type,
|
|
170
|
-
data: new Uint8Array(chunk.data),
|
|
171
|
-
timestamp: chunk.timestamp
|
|
172
|
-
};
|
|
173
|
-
if ('configuration' === packet.type) {
|
|
174
|
-
configurationPacketSent = true;
|
|
175
|
-
controller.enqueue(packet);
|
|
176
|
-
pendingDataPackets.forEach((queuedPacket)=>controller.enqueue(queuedPacket));
|
|
177
|
-
pendingDataPackets = [];
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
if ('data' === packet.type && !configurationPacketSent) return void pendingDataPackets.push(packet);
|
|
181
|
-
controller.enqueue(packet);
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
let cleanupListeners;
|
|
185
|
-
const readable = new ReadableStream({
|
|
186
|
-
start (controller) {
|
|
187
|
-
const handleVideoData = (data)=>{
|
|
188
|
-
try {
|
|
189
|
-
controller.enqueue(data);
|
|
190
|
-
} catch (error) {
|
|
191
|
-
controller.error(error);
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
const handleDisconnect = ()=>controller.close();
|
|
195
|
-
const handleError = (error)=>controller.error(error);
|
|
196
|
-
cleanupListeners = ()=>{
|
|
197
|
-
null == socket || socket.off('video-data', handleVideoData);
|
|
198
|
-
null == socket || socket.off('disconnect', handleDisconnect);
|
|
199
|
-
null == socket || socket.off('error', handleError);
|
|
200
|
-
};
|
|
201
|
-
null == socket || socket.on('video-data', handleVideoData);
|
|
202
|
-
null == socket || socket.on('disconnect', handleDisconnect);
|
|
203
|
-
null == socket || socket.on('error', handleError);
|
|
204
|
-
},
|
|
205
|
-
cancel () {
|
|
206
|
-
null == cleanupListeners || cleanupListeners();
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
return readable.pipeThrough(transformStream);
|
|
210
|
-
};
|
|
211
163
|
const connect = ()=>{
|
|
212
164
|
if (disposed) return;
|
|
213
165
|
manuallyDisconnectedRef.current = false;
|
|
@@ -220,6 +172,7 @@ function ScrcpyPanel({ serverUrl, reconnectInterval = 3000 }) {
|
|
|
220
172
|
timeout: 10000
|
|
221
173
|
});
|
|
222
174
|
socketRef.current = socket;
|
|
175
|
+
const videoStream = (0, external_scrcpy_stream_js_namespaceObject.createScrcpyVideoStream)(socket);
|
|
223
176
|
socket.on('connect', ()=>{
|
|
224
177
|
socket.emit('connect-device', {
|
|
225
178
|
maxSize: 1024
|
|
@@ -235,7 +188,7 @@ function ScrcpyPanel({ serverUrl, reconnectInterval = 3000 }) {
|
|
|
235
188
|
width: metadata.width,
|
|
236
189
|
height: metadata.height
|
|
237
190
|
});
|
|
238
|
-
|
|
191
|
+
videoStream.pipeTo(decoder.writable).catch((error)=>{
|
|
239
192
|
if (disposed) return;
|
|
240
193
|
setStatus('error');
|
|
241
194
|
setErrorMessage(error.message);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
createScrcpyVideoStream: ()=>createScrcpyVideoStream
|
|
28
|
+
});
|
|
29
|
+
function createScrcpyVideoStream(socket) {
|
|
30
|
+
let configurationPacketSent = false;
|
|
31
|
+
let pendingDataPackets = [];
|
|
32
|
+
const transformStream = new TransformStream({
|
|
33
|
+
transform (chunk, controller) {
|
|
34
|
+
if ('configuration' === chunk.type) {
|
|
35
|
+
configurationPacketSent = true;
|
|
36
|
+
controller.enqueue(chunk);
|
|
37
|
+
pendingDataPackets.forEach((queuedPacket)=>controller.enqueue(queuedPacket));
|
|
38
|
+
pendingDataPackets = [];
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if ('data' === chunk.type && !configurationPacketSent) return void pendingDataPackets.push(chunk);
|
|
42
|
+
controller.enqueue(chunk);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
let cleanupListeners;
|
|
46
|
+
const readable = new ReadableStream({
|
|
47
|
+
start (controller) {
|
|
48
|
+
const handleVideoData = (data)=>{
|
|
49
|
+
try {
|
|
50
|
+
const payload = new Uint8Array(data.data);
|
|
51
|
+
if ('configuration' === data.type) return void controller.enqueue({
|
|
52
|
+
type: 'configuration',
|
|
53
|
+
data: payload
|
|
54
|
+
});
|
|
55
|
+
controller.enqueue({
|
|
56
|
+
type: 'data',
|
|
57
|
+
data: payload,
|
|
58
|
+
keyframe: data.keyFrame
|
|
59
|
+
});
|
|
60
|
+
} catch (error) {
|
|
61
|
+
controller.error(error);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const handleDisconnect = ()=>controller.close();
|
|
65
|
+
const handleError = (error)=>controller.error(error);
|
|
66
|
+
cleanupListeners = ()=>{
|
|
67
|
+
socket.off('video-data', handleVideoData);
|
|
68
|
+
socket.off('disconnect', handleDisconnect);
|
|
69
|
+
socket.off('error', handleError);
|
|
70
|
+
};
|
|
71
|
+
socket.on('video-data', handleVideoData);
|
|
72
|
+
socket.on('disconnect', handleDisconnect);
|
|
73
|
+
socket.on('error', handleError);
|
|
74
|
+
},
|
|
75
|
+
cancel () {
|
|
76
|
+
null == cleanupListeners || cleanupListeners();
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
return readable.pipeThrough(transformStream);
|
|
80
|
+
}
|
|
81
|
+
exports.createScrcpyVideoStream = __webpack_exports__.createScrcpyVideoStream;
|
|
82
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
83
|
+
"createScrcpyVideoStream"
|
|
84
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
85
|
+
Object.defineProperty(exports, '__esModule', {
|
|
86
|
+
value: true
|
|
87
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
resolveAutoCreateSessionInput: ()=>resolveAutoCreateSessionInput
|
|
28
|
+
});
|
|
29
|
+
const external_session_state_js_namespaceObject = require("./session-state.js");
|
|
30
|
+
function hasSessionFieldValue(value) {
|
|
31
|
+
return null != value && '' !== value;
|
|
32
|
+
}
|
|
33
|
+
function resolveAutoCreateSessionInput(setup, existingValues = {}) {
|
|
34
|
+
if (!(null == setup ? void 0 : setup.autoSubmitWhenReady)) return null;
|
|
35
|
+
const values = (0, external_session_state_js_namespaceObject.buildSessionInitialValues)(setup, existingValues);
|
|
36
|
+
for (const field of setup.fields)if (field.required) {
|
|
37
|
+
if (!hasSessionFieldValue(values[field.key])) return null;
|
|
38
|
+
}
|
|
39
|
+
return values;
|
|
40
|
+
}
|
|
41
|
+
exports.resolveAutoCreateSessionInput = __webpack_exports__.resolveAutoCreateSessionInput;
|
|
42
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
43
|
+
"resolveAutoCreateSessionInput"
|
|
44
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
45
|
+
Object.defineProperty(exports, '__esModule', {
|
|
46
|
+
value: true
|
|
47
|
+
});
|
|
@@ -61,6 +61,13 @@ function useServerStatus(playgroundSDK, defaultDeviceType, pollIntervalMs) {
|
|
|
61
61
|
const [runtimeInfo, setRuntimeInfo] = (0, external_react_namespaceObject.useState)(null);
|
|
62
62
|
const [executionUxHints, setExecutionUxHints] = (0, external_react_namespaceObject.useState)([]);
|
|
63
63
|
const runtimeInfoRef = (0, external_react_namespaceObject.useRef)(null);
|
|
64
|
+
const mountedRef = (0, external_react_namespaceObject.useRef)(true);
|
|
65
|
+
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
66
|
+
mountedRef.current = true;
|
|
67
|
+
return ()=>{
|
|
68
|
+
mountedRef.current = false;
|
|
69
|
+
};
|
|
70
|
+
}, []);
|
|
64
71
|
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
65
72
|
runtimeInfoRef.current = runtimeInfo;
|
|
66
73
|
}, [
|
|
@@ -73,65 +80,69 @@ function useServerStatus(playgroundSDK, defaultDeviceType, pollIntervalMs) {
|
|
|
73
80
|
}, [
|
|
74
81
|
playgroundSDK
|
|
75
82
|
]);
|
|
76
|
-
(0, external_react_namespaceObject.
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
const refreshServerState = (0, external_react_namespaceObject.useCallback)(()=>_async_to_generator(function*() {
|
|
84
|
+
try {
|
|
85
|
+
const online = yield playgroundSDK.checkStatus();
|
|
86
|
+
if (!mountedRef.current) return;
|
|
87
|
+
setServerOnline(online);
|
|
88
|
+
if (!online) {
|
|
89
|
+
runtimeInfoRef.current = null;
|
|
90
|
+
setRuntimeInfo(null);
|
|
91
|
+
setExecutionUxHints([]);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
79
94
|
try {
|
|
80
|
-
const
|
|
81
|
-
if (!
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
setExecutionUxHints(
|
|
95
|
+
const nextRuntimeInfo = yield playgroundSDK.getRuntimeInfo();
|
|
96
|
+
if (!mountedRef.current) return;
|
|
97
|
+
if (nextRuntimeInfo) {
|
|
98
|
+
runtimeInfoRef.current = nextRuntimeInfo;
|
|
99
|
+
setRuntimeInfo(nextRuntimeInfo);
|
|
100
|
+
setDeviceType((0, external_runtime_info_js_namespaceObject.normalizeRuntimeDeviceType)(nextRuntimeInfo, defaultDeviceType));
|
|
101
|
+
setExecutionUxHints((0, external_runtime_info_js_namespaceObject.filterValidExecutionUxHints)(nextRuntimeInfo));
|
|
87
102
|
return;
|
|
88
103
|
}
|
|
89
|
-
try {
|
|
90
|
-
const nextRuntimeInfo = yield playgroundSDK.getRuntimeInfo();
|
|
91
|
-
if (!active) return;
|
|
92
|
-
if (nextRuntimeInfo) {
|
|
93
|
-
setRuntimeInfo(nextRuntimeInfo);
|
|
94
|
-
setDeviceType((0, external_runtime_info_js_namespaceObject.normalizeRuntimeDeviceType)(nextRuntimeInfo, defaultDeviceType));
|
|
95
|
-
setExecutionUxHints((0, external_runtime_info_js_namespaceObject.filterValidExecutionUxHints)(nextRuntimeInfo));
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
} catch (error) {
|
|
99
|
-
console.warn('Failed to get runtime info:', error);
|
|
100
|
-
}
|
|
101
|
-
try {
|
|
102
|
-
const interfaceInfo = yield playgroundSDK.getInterfaceInfo();
|
|
103
|
-
if (!active || !(null == interfaceInfo ? void 0 : interfaceInfo.type)) return;
|
|
104
|
-
const fallbackRuntimeInfo = (0, external_runtime_info_js_namespaceObject.buildFallbackRuntimeInfo)(runtimeInfoRef.current, interfaceInfo);
|
|
105
|
-
runtimeInfoRef.current = fallbackRuntimeInfo;
|
|
106
|
-
setRuntimeInfo(fallbackRuntimeInfo);
|
|
107
|
-
setDeviceType((0, external_runtime_info_js_namespaceObject.normalizeRuntimeDeviceType)(fallbackRuntimeInfo, defaultDeviceType));
|
|
108
|
-
setExecutionUxHints((0, external_runtime_info_js_namespaceObject.filterValidExecutionUxHints)(fallbackRuntimeInfo));
|
|
109
|
-
} catch (error) {
|
|
110
|
-
console.warn('Failed to get interface info:', error);
|
|
111
|
-
}
|
|
112
104
|
} catch (error) {
|
|
113
|
-
|
|
114
|
-
console.error('Failed to check server status:', error);
|
|
115
|
-
setServerOnline(false);
|
|
105
|
+
console.warn('Failed to get runtime info:', error);
|
|
116
106
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
107
|
+
try {
|
|
108
|
+
const interfaceInfo = yield playgroundSDK.getInterfaceInfo();
|
|
109
|
+
if (!mountedRef.current || !(null == interfaceInfo ? void 0 : interfaceInfo.type)) return;
|
|
110
|
+
const fallbackRuntimeInfo = (0, external_runtime_info_js_namespaceObject.buildFallbackRuntimeInfo)(runtimeInfoRef.current, interfaceInfo);
|
|
111
|
+
runtimeInfoRef.current = fallbackRuntimeInfo;
|
|
112
|
+
setRuntimeInfo(fallbackRuntimeInfo);
|
|
113
|
+
setDeviceType((0, external_runtime_info_js_namespaceObject.normalizeRuntimeDeviceType)(fallbackRuntimeInfo, defaultDeviceType));
|
|
114
|
+
setExecutionUxHints((0, external_runtime_info_js_namespaceObject.filterValidExecutionUxHints)(fallbackRuntimeInfo));
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.warn('Failed to get interface info:', error);
|
|
117
|
+
}
|
|
118
|
+
} catch (error) {
|
|
119
|
+
if (!mountedRef.current) return;
|
|
120
|
+
console.error('Failed to check server status:', error);
|
|
121
|
+
setServerOnline(false);
|
|
122
|
+
}
|
|
123
|
+
})(), [
|
|
124
|
+
defaultDeviceType,
|
|
125
|
+
playgroundSDK
|
|
126
|
+
]);
|
|
127
|
+
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
128
|
+
refreshServerState();
|
|
129
|
+
const interval = window.setInterval(()=>{
|
|
130
|
+
refreshServerState();
|
|
131
|
+
}, pollIntervalMs);
|
|
120
132
|
return ()=>{
|
|
121
|
-
active = false;
|
|
122
133
|
window.clearInterval(interval);
|
|
123
134
|
};
|
|
124
135
|
}, [
|
|
125
|
-
playgroundSDK,
|
|
126
136
|
pollIntervalMs,
|
|
127
|
-
|
|
137
|
+
refreshServerState
|
|
128
138
|
]);
|
|
129
139
|
return {
|
|
130
140
|
serverOnline,
|
|
131
141
|
isUserOperating,
|
|
132
142
|
deviceType,
|
|
133
143
|
runtimeInfo,
|
|
134
|
-
executionUxHints
|
|
144
|
+
executionUxHints,
|
|
145
|
+
refreshServerState
|
|
135
146
|
};
|
|
136
147
|
}
|
|
137
148
|
exports.useServerStatus = __webpack_exports__.useServerStatus;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ScrcpyMediaStreamPacket } from '@yume-chan/scrcpy';
|
|
2
|
+
interface RawScrcpyVideoPacket {
|
|
3
|
+
type?: string;
|
|
4
|
+
data: ArrayLike<number>;
|
|
5
|
+
keyFrame?: boolean;
|
|
6
|
+
}
|
|
7
|
+
interface ScrcpyVideoSocketLike {
|
|
8
|
+
on(event: 'video-data', handler: (data: RawScrcpyVideoPacket) => void): void;
|
|
9
|
+
on(event: 'disconnect', handler: () => void): void;
|
|
10
|
+
on(event: 'error', handler: (error: Error) => void): void;
|
|
11
|
+
off(event: 'video-data', handler: (data: RawScrcpyVideoPacket) => void): void;
|
|
12
|
+
off(event: 'disconnect', handler: () => void): void;
|
|
13
|
+
off(event: 'error', handler: (error: Error) => void): void;
|
|
14
|
+
}
|
|
15
|
+
export declare function createScrcpyVideoStream(socket: ScrcpyVideoSocketLike): ReadableStream<ScrcpyMediaStreamPacket>;
|
|
16
|
+
export {};
|
|
@@ -6,6 +6,7 @@ interface ServerStatusResult {
|
|
|
6
6
|
deviceType: DeviceType;
|
|
7
7
|
runtimeInfo: PlaygroundRuntimeInfo | null;
|
|
8
8
|
executionUxHints: ExecutionUxHint[];
|
|
9
|
+
refreshServerState: () => Promise<void>;
|
|
9
10
|
}
|
|
10
11
|
export declare function useServerStatus(playgroundSDK: PlaygroundSDK, defaultDeviceType: DeviceType, pollIntervalMs: number): ServerStatusResult;
|
|
11
12
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/playground-app",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Reusable React shell for Midscene playground applications",
|
|
5
5
|
"repository": "https://github.com/web-infra-dev/midscene",
|
|
6
6
|
"homepage": "https://midscenejs.com/",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"antd": "^5.21.6",
|
|
29
29
|
"react-resizable-panels": "2.0.22",
|
|
30
30
|
"socket.io-client": "4.8.1",
|
|
31
|
-
"@midscene/playground": "1.
|
|
32
|
-
"@midscene/visualizer": "1.
|
|
31
|
+
"@midscene/playground": "1.7.0",
|
|
32
|
+
"@midscene/visualizer": "1.7.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@rsbuild/plugin-less": "^1.5.0",
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"less": "^4.2.0",
|
|
44
44
|
"react": "18.3.1",
|
|
45
45
|
"react-dom": "18.3.1",
|
|
46
|
-
"typescript": "^5.8.3"
|
|
46
|
+
"typescript": "^5.8.3",
|
|
47
|
+
"vitest": "3.0.5"
|
|
47
48
|
},
|
|
48
49
|
"sideEffects": [
|
|
49
50
|
"**/*.css",
|
|
@@ -58,6 +59,8 @@
|
|
|
58
59
|
"scripts": {
|
|
59
60
|
"dev": "npm run build:watch",
|
|
60
61
|
"build": "rslib build",
|
|
61
|
-
"build:watch": "rslib build --watch --no-clean"
|
|
62
|
+
"build:watch": "rslib build --watch --no-clean",
|
|
63
|
+
"test": "vitest --run",
|
|
64
|
+
"test:watch": "vitest"
|
|
62
65
|
}
|
|
63
66
|
}
|