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;