diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b9e97eb9..d644d87b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,9 +31,10 @@ jobs: - run: yarn run eslint . --ext ts,tsx --max-warnings 0 - run: mkdir -p public/emulators && cp -rv node_modules/emulators/dist/* public/emulators - run: NODE_ENV=production yarn run vite build --base /latest --sourcemap true --minify terser + - run: zip -9r release.zip dist/* - name: publish if: startsWith(github.ref, 'refs/tags/') - run: npm publish --tag beta + run: npm publish env: NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}} - name: upload @@ -41,3 +42,10 @@ jobs: with: name: 'dist' path: 'dist' + - name: Release + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + with: + name: ${{ github.ref_name }} + files: | + ${{github.workspace}}/release.zip diff --git a/package.json b/package.json index f165fae3..b2d44898 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "js-dos", - "version": "0.80.26", + "version": "8.1.0", "description": "Full-featured DOS player with multiple emulator backends", "type": "module", "keywords": [ @@ -35,7 +35,7 @@ "@typescript-eslint/parser": "^6.20.0", "autoprefixer": "^10.4.17", "daisyui": "^3.9.3", - "emulators": "8.1.1", + "emulators": "8.1.2", "eslint": "^8.56.0", "eslint-config-google": "^0.14.0", "postcss": "^8.4.33", diff --git a/src/i18n.ts b/src/i18n.ts index 4bd96725..ffbb58e3 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -4,6 +4,7 @@ import { State } from "./store"; const translations: {[lang: string]: {[key: string]: string} } = { ru: { + preloading_sockdrive: "Загрузка FAT", filter: "Фильтр", add: "Добавить", logout: "Выйти", @@ -74,6 +75,7 @@ const translations: {[lang: string]: {[key: string]: string} } = { fat_write: "FAT запись", }, en: { + preloading_sockdrive: "Preloading FAT", filter: "Filter", add: "Add", logout: "Logout", diff --git a/src/sockdrive b/src/sockdrive index bb038ed9..93e786f8 160000 --- a/src/sockdrive +++ b/src/sockdrive @@ -1 +1 @@ -Subproject commit bb038ed9a5891b7b11acf09b7fba13a6b4104b32 +Subproject commit 93e786f8aab900872f05530e9aada8a82416d2a9 diff --git a/src/store/ui.ts b/src/store/ui.ts index 7da6642f..0b8e83d8 100644 --- a/src/store/ui.ts +++ b/src/store/ui.ts @@ -116,7 +116,8 @@ export const uiSlice = createSlice({ setFullScreen: (state, a: { payload: boolean }) => { state.fullScreen = a.payload; }, - showToast: (state, a: { payload: { message: string, intent?: typeof initialState.toastIntent } }) => { + showToast: (state, a: { payload: { message: string, intent?: typeof initialState.toastIntent, + long?: boolean } }) => { if (state.toastTimeoutId !== 0) { clearInterval(state.toastTimeoutId); } @@ -125,7 +126,7 @@ export const uiSlice = createSlice({ if (a.payload.intent !== "panic") { state.toastTimeoutId = setTimeout(() => { (a as unknown as DosAction).asyncStore((store) => store.dispatch(uiSlice.actions.hideToast())); - }, 1500); + }, a.payload.long ? 5000 : 1500); } }, hideToast: (state) => { diff --git a/src/ui.tsx b/src/ui.tsx index f18426da..7f940ba2 100644 --- a/src/ui.tsx +++ b/src/ui.tsx @@ -55,12 +55,13 @@ export function Ui() { function Toast() { const toast = useSelector((state: State) => state.ui.toast); const intent = useSelector((state: State) => state.ui.toastIntent); + const readOnlyWarning = useSelector((state: State) => state.ui.readOnlyWarning); if (toast === null) { return null; } - return
+ return
{toast}
diff --git a/src/window/dos/dos-runtime.tsx b/src/window/dos/dos-runtime.tsx index 8f20d81b..0a395c2c 100644 --- a/src/window/dos/dos-runtime.tsx +++ b/src/window/dos/dos-runtime.tsx @@ -10,6 +10,7 @@ import { useEffect } from "preact/hooks"; import { mouse } from "./controls/mouse"; import { KBD_0 } from "./controls/keys"; import { uiSlice } from "../../store/ui"; +import { useT } from "../../i18n"; export function useDosRuntime(canvas: HTMLCanvasElement, ci: CommandInterface): void { @@ -25,19 +26,44 @@ export function useDosRuntime(canvas: HTMLCanvasElement, function useLog(ci: CommandInterface): void { const dispatch = useDispatch(); + const t = useT(); useEffect(() => { - ci.events().onMessage((msgType, ...args) => { + let totalPreload = 0; + const preloadProgress: { [drive: string]: number } = {}; + ci.events().onMessage((msgType, ...args: string[]) => { if (msgType === "error" && args[0]?.startsWith("[panic]")) { dispatch(uiSlice.actions.showToast({ message: args[0], intent: "panic", })); } else if (msgType === "log" && args[0]?.indexOf("sockdrive:") !== -1) { + const drive = args[0].substring(args[0].indexOf(" ") + 1, args[0].indexOf(",")); dispatch(uiSlice.actions.cloudSaves(false)); if (args[0]?.indexOf("write=false") !== -1) { + console.log("drive", drive, "config:", args[0]); dispatch(uiSlice.actions.readOnlyWarning(true)); } - console.log(...args); + if (args[0]?.indexOf("preload=") !== -1) { + const rest = Number.parseInt(args[0].substring(args[0].indexOf("preload=") + "preload=".length)); + if (preloadProgress[drive] === undefined) { + preloadProgress[drive] = rest; + totalPreload += rest; + } else { + preloadProgress[drive] = rest; + } + + let downloaded = totalPreload; + for (const rest of Object.values(preloadProgress)) { + downloaded -= rest; + } + + dispatch(uiSlice.actions.showToast({ + message: t("preloading_sockdrive") + " " + + (Math.round(downloaded / 1024 / 1024 * 100) / 100) + "/" + + (Math.round(totalPreload / 1024 / 1024 * 100) / 100) + "Mb", + long: true, + })); + } } }); }, [ci, dispatch]); diff --git a/src/ws/ws-sockdrive.ts b/src/ws/ws-sockdrive.ts index 373c639d..50bad558 100644 --- a/src/ws/ws-sockdrive.ts +++ b/src/ws/ws-sockdrive.ts @@ -51,8 +51,7 @@ export function createSockdrive( const sectorSize = templates[seq].sectorSize; memory[seq] = new Uint8Array(sectorSize + sectorSize * aheadRange); - mapping[seq] = new Drive(url, owner, name, token, stats, - { HEAPU8: memory[seq] }, sectorSize, aheadRange, sectorSize, 1); // cache is on server + mapping[seq] = new Drive(url, owner, name, token, stats, { HEAPU8: memory[seq] }); mapping[seq].onOpen((read, write) => { onOpen(owner + "/" + name, read, write); }); diff --git a/yarn.lock b/yarn.lock index 5de9160d..d0e72704 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1154,10 +1154,10 @@ electron-to-chromium@^1.4.648: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.653.tgz#832ab25e80ad698ac09c1ca547bd9ee6cce7df10" integrity sha512-wA2A2LQCqnEwQAvwADQq3KpMpNwgAUBnRmrFgRzHnPhbQUFArTR32Ab46f4p0MovDLcg4uqd4nCsN2hTltslpA== -emulators@8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/emulators/-/emulators-8.1.1.tgz#69d9e42e5590b6dbd5db7ab90ae412d8bbc5bc8f" - integrity sha512-OHR/vuE3yDMRmmgtPhAxZwh/MuCkae3wnoaskuT0EvXRe7iJC5GPzZr5PtHT7VVt9oTdbvMppXqRc1kN0olynA== +emulators@8.1.2: + version "8.1.2" + resolved "https://registry.yarnpkg.com/emulators/-/emulators-8.1.2.tgz#15dfc1045f0b05ccda70a49be59ae435db5f15ea" + integrity sha512-1cagI2XUN8b3TixCyERjr+wRWfcnM5a00i8ZM20kRhZp4zfvNo/CNgAyyJS9xxW5DGpNct9iTAVYCND7oZK9ZQ== entities@^4.2.0: version "4.5.0"