diff --git a/index.html b/index.html index b9e88345..e8ecd1c8 100644 --- a/index.html +++ b/index.html @@ -73,6 +73,14 @@ pathPrefix: "/emulators/", server: params.get("server"), room: params.get("room"), + // ipx: [{ + // name: "my-ipx-server", + // host: "wss://some.url", + // }, { + // name: "dos.zone", + // host: "wss://netherlands.dos.zone", + // } + // ], // backendHardware: (backend) => { // console.log("Hardware backend for", backend); // return Promise.resolve("ws://127.0.0.1:8888"); diff --git a/package.json b/package.json index 2fe03ad9..afa5e790 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "js-dos", - "version": "8.3.7", + "version": "8.3.8", "description": "Full-featured DOS player with multiple emulator backends", "type": "module", "keywords": [ diff --git a/src/frame/network-frame.tsx b/src/frame/network-frame.tsx index 55d6fef4..270aa2e0 100644 --- a/src/frame/network-frame.tsx +++ b/src/frame/network-frame.tsx @@ -8,33 +8,35 @@ import { uiSlice } from "../store/ui"; import { Dispatch } from "@reduxjs/toolkit"; export function NetworkFrame() { - const network = useSelector((state: State) => state.dos.network); + const network = useSelector((state: State) => state.dos.ipx); + const backends = network.backends; + const selected = network.backend; const room = network.room; - const server = network.server; - const disabled = network.ipx !== "disconnected"; + const backend = network.backends.find((v) => v.name === selected) ?? backends[0]; + const disabled = network.status !== "disconnected"; const t = useT(); const dispatch = useDispatch(); const ipxLink = - network.ipx === "connected" ? + network.status === "connected" ? location.href + searchSeparator() + - "ipx=1&server=" + network.server + "&room=" + room : + "ipx=1&server=" + selected + "&room=" + room : null; function setRoom(room: string) { dispatch(dosSlice.actions.setRoom(room)); } - function setServer(server: string) { - dispatch(dosSlice.actions.setServer(server as any)); + function setIpxBackend(backend: string) { + dispatch(dosSlice.actions.setIpxBackend(backend)); } function toggleIpx() { - if (network.ipx === "connected") { + if (network.status === "connected") { dispatch(dosSlice.actions.disconnectIpx({})); } else { dispatch(dosSlice.actions.connectIpx({ room, - address: "wss://" + server + ".dos.zone", + address: backend.host, }) as any); } } @@ -47,7 +49,7 @@ export function NetworkFrame() { } function onServer(newServer: string) { - setServer(newServer); + setIpxBackend(newServer); } return
@@ -56,8 +58,8 @@ export function NetworkFrame() { class="text-sm" selectClass="w-full" label={t("server") + ":"} - selected={server} - values={["netherlands"]} + selected={backend.name} + values={backends.map((b) => b.name)} disabled={disabled} onSelect={onServer} /> @@ -73,12 +75,12 @@ export function NetworkFrame() { value={room}>
{ipxLink !== null &&
diff --git a/src/main.tsx b/src/main.tsx index 1804161b..b172ae91 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -105,8 +105,12 @@ export const Dos: DosFn = (element: HTMLDivElement, store.dispatch(dosSlice.actions.mouseCapture(capture)); } - function setServer(server: DosOptions["server"]) { - store.dispatch(dosSlice.actions.setServer(server)); + function setIpx(backends: DosOptions["ipx"]) { + store.dispatch(dosSlice.actions.setIpxBackends(backends)); + } + + function setIpxBackend(backend: string) { + store.dispatch(dosSlice.actions.setIpxBackend(backend)); } function setRoom(room: DosOptions["room"]) { @@ -211,8 +215,8 @@ export const Dos: DosFn = (element: HTMLDivElement, setWorkerThread(options.workerThread); } - if (options.server) { - setServer(options.server); + if (options.ipx) { + setIpx(options.ipx); } if (options.room) { @@ -297,7 +301,8 @@ export const Dos: DosFn = (element: HTMLDivElement, setBackendLocked, setWorkerThread, setMouseCapture, - setServer, + setIpx, + setIpxBackend, setRoom, setFrame, setBackground, diff --git a/src/public/types.ts b/src/public/types.ts index d4dcd04f..39ad9fda 100644 --- a/src/public/types.ts +++ b/src/public/types.ts @@ -12,6 +12,11 @@ export interface InitFileEntry { export type InitFsEntry = InitBundleEntry | InitFileEntry; export type InitFs = InitFsEntry | InitFsEntry[]; +export interface NamedHost { + name: string, + host: string, +} + export interface DosOptions { url: string, dosboxConf: string, @@ -31,13 +36,10 @@ export interface DosOptions { workerThread: boolean, mouseCapture: boolean, onEvent: (event: DosEvent, ci?: any /* CommandInterface */) => void, - server: "netherlands", + ipx: NamedHost[], room: string, fullScreen: boolean, - sockdriveBackend: { - name: string, - host: string, - }, + sockdriveBackend: NamedHost, autoStart: boolean, kiosk: boolean, imageRendering: ImageRendering, @@ -61,7 +63,8 @@ export interface DosProps { setBackendLocked(locked: boolean): void; setWorkerThread(capture: DosOptions["workerThread"]): void; setMouseCapture(capture: DosOptions["mouseCapture"]): void; - setServer(server: DosOptions["server"]): void; + setIpx(ipx: DosOptions["ipx"]): void; + setIpxBackend(backend: string): void; setRoom(room: DosOptions["room"]): void; setFrame(frame: "network"): void; setBackground(background: string | null): void; diff --git a/src/sidebar/network-button.tsx b/src/sidebar/network-button.tsx index 5e85bb76..64ccdddc 100644 --- a/src/sidebar/network-button.tsx +++ b/src/sidebar/network-button.tsx @@ -6,7 +6,7 @@ export function NetworkButton(props: { class?: string, }) { const hightlight = useSelector((state: State) => state.ui.frame) === "network"; - const inactive = useSelector((state: State) => state.dos.network.ipx !== "connected"); + const inactive = useSelector((state: State) => state.dos.ipx.status !== "connected"); const dispatch = useDispatch(); function onClick() { diff --git a/src/store/dos.ts b/src/store/dos.ts index bdbd0a80..731fa8bc 100644 --- a/src/store/dos.ts +++ b/src/store/dos.ts @@ -2,6 +2,7 @@ import { createSlice } from "@reduxjs/toolkit"; import { DosAction, getNonSerializableStore, makeStore, postJsDosEvent } from "../store"; import { Emulators } from "emulators"; import { lStorage } from "../host/lstorage"; +import { NamedHost } from "../public/types"; const alphabet = "qwertyuiopasdfghjklzxcvbnm1234567890"; declare const emulators: Emulators; @@ -71,10 +72,11 @@ const initialState: { stats: EmulatorStats, ci: boolean, ciStartedAt: number, - network: { - server: "netherlands", + ipx: { + backends: NamedHost[], + backend: string, room: string, - ipx: "connecting" | "connected" | "disconnected" | "error", + status: "connecting" | "connected" | "disconnected" | "error", }, imageRendering: ImageRendering, sockdriveWrite: boolean, @@ -125,10 +127,14 @@ const initialState: { driveBufferedAmount: 0, driveIo: [], }, - network: { - server: "netherlands", + ipx: { + backends: [{ + name: "dos.zone", + host: "wss://netherlands.dos.zone", + }], + backend: lStorage.getItem("net.ipx.server") ?? "netherlands", room: randomRoom(), - ipx: "disconnected", + status: "disconnected", }, ci: false, ciStartedAt: 0, @@ -295,7 +301,7 @@ export const dosSlice = createSlice({ } }, connectIpx: (s, a: { payload: { room: string, address: string } }) => { - if (s.network.ipx === "connected") { + if (s.ipx.status === "connected") { throw new Error("Already connected"); } @@ -304,7 +310,7 @@ export const dosSlice = createSlice({ } const { room, address } = a.payload; - s.network.ipx = "connecting"; + s.ipx.status = "connecting"; (a as unknown as DosAction).asyncStore((store) => { const nonSerializableStore = getNonSerializableStore(store); if (!nonSerializableStore.ci) { @@ -327,20 +333,33 @@ export const dosSlice = createSlice({ }); }, statusIpx: (s, a: { payload: "error" | "connected" | "connecting" }) => { - s.network.ipx = a.payload; + s.ipx.status = a.payload; }, disconnectIpx: (s, a) => { - s.network.ipx = "disconnected"; + s.ipx.status = "disconnected"; (a as unknown as DosAction).asyncStore((store) => { getNonSerializableStore(store).ci?.networkDisconnect(0 /* IPX */); }); }, setRoom: (s, a: { payload: string }) => { - s.network.room = a.payload; + s.ipx.room = a.payload; }, - setServer: (s, a: { payload: typeof initialState.network.server }) => { - s.network.server = a.payload; - lStorage.setItem("net.server", a.payload); + setIpxBackends: (s, a: { payload: NamedHost[] }) => { + s.ipx.backends = a.payload; + const selected = lStorage.getItem("net.ipx.server"); + if (selected !== null && a.payload.find((b) => b.name === selected) !== undefined) { + s.ipx.backend = selected; + } else { + s.ipx.backend = a.payload[0].name; + lStorage.setItem("net.ipx.server", s.ipx.backend); + } + }, + setIpxBackend: (s, a: { payload: string }) => { + const backend = s.ipx.backends.find((v) => v.name === a.payload); + if (backend) { + s.ipx.backend = backend.name; + lStorage.setItem("net.ipx.server", a.payload); + } }, setSockdriveWrite: (s, a: { payload: boolean }) => { s.sockdriveWrite = a.payload;