fix: Cleanup

This commit is contained in:
Felix Rieseberg 2019-02-03 13:49:09 -08:00
parent ed1bd0a1e0
commit 6467acb0c8
11 changed files with 204 additions and 82 deletions

22
src/constants.js Normal file
View file

@ -0,0 +1,22 @@
const { remote, app } = require('electron')
const path = require('path')
const _app = app || remote.app
const CONSTANTS = {
IMAGE_PATH: path.join(__dirname, 'images/windows95.img'),
IMAGE_DEFAULT_SIZE: 1073741824, // 1GB
STATE_PATH: path.join(_app.getPath('userData'), 'state.bin')
}
const IPC_COMMANDS = {
TOGGLE_INFO: 'TOGGLE_INFO',
MACHINE_RESTART: 'MACHINE_RESTART',
MACHINE_CTRL_ALT_DEL: 'MACHINE_CTRL_ALT_DEL',
SHOW_DISK_IMAGE: 'SHOW_DISK_IMAGE'
}
module.exports = {
CONSTANTS,
IPC_COMMANDS
}

View file

@ -1,45 +1,42 @@
const { remote, shell, ipcRenderer } = require('electron')
const path = require('path')
const EventEmitter = require('events')
const { STATE_PATH, resetState, restoreState, saveState } = require('./state')
const { resetState, restoreState, saveState } = require('./state')
const { getDiskImageSize } = require('./utils/disk-image-size')
const { IPC_COMMANDS, CONSTANTS } = require('./constants')
window.windows95 = {
STATE_PATH,
restoreState,
resetState,
saveState,
class Windows95 extends EventEmitter {
constructor () {
super()
// Constants
this.CONSTANTS = CONSTANTS
// Methods
this.getDiskImageSize = getDiskImageSize
this.restoreState = restoreState
this.resetState = resetState
this.saveState = saveState
Object.keys(IPC_COMMANDS).forEach((command) => {
ipcRenderer.on(command, (...args) => {
this.emit(command, args)
})
})
}
showDiskImage () {
const imagePath = path.join(__dirname, 'images/windows95.img')
.replace('app.asar', 'app.asar.unpacked')
shell.showItemInFolder(imagePath)
},
}
quit: () => remote.app.quit()
quit () {
remote.app.quit()
}
}
ipcRenderer.on('ctrlaltdel', () => {
if (!window.emulator || !window.emulator.is_running) return
window.windows95 = new Windows95()
window.emulator.keyboard_send_scancodes([
0x1D, // ctrl
0x38, // alt
0x53, // delete
// break codes
0x1D | 0x80,
0x38 | 0x80,
0x53 | 0x80
])
})
ipcRenderer.on('restart', () => {
if (!window.emulator || !window.emulator.is_running) return
window.emulator.restart()
})
ipcRenderer.on('disk-image', () => {
windows95.showDiskImage()
})

View file

@ -2,7 +2,6 @@ export function setupState () {
window.appState = {
cursorCaptured: false,
floppyFile: null,
bootFresh: false,
infoInterval: null
bootFresh: false
}
}

Binary file not shown.

Binary file not shown.

View file

@ -14,7 +14,7 @@
<div id="status">
Disk: <span id="disk-status">Idle</span>
| CPU Speed: <span id="cpu-status">0</span>
| <a onclick="document.querySelector('#status').style.display='none'">Hide</a>
| <a href="#" id="toggle-status">Hide</a>
</div>
<div id="buttons">
<div id="start-buttons">

View file

@ -1,28 +1,56 @@
const $ = document.querySelector.bind(document)
const status = $('#status')
const diskStatus = $('#disk-status')
const cpuStatus = $('#cpu-status')
const toggleStatus = $('#toggle-status')
export function setupInfo () {
const diskStatus = $('#disk-status')
const cpuStatus = $('#cpu-status')
let lastCounter = 0
let lastTick = 0
let lastCounter = 0
let lastTick = 0
let infoInterval = null
window.emulator.add_listener('ide-read-start', () => {
diskStatus.innerHTML = 'Read'
})
const onIDEReadStart = () => {
diskStatus.innerHTML = 'Read'
}
window.emulator.add_listener('ide-read-end', () => {
diskStatus.innerHTML = 'Idle'
})
const onIDEReadWriteEnd = () => {
diskStatus.innerHTML = 'Idle'
}
window.emulator.add_listener('ide-write-end', () => {
diskStatus.innerHTML = 'Idle'
})
toggleStatus.onclick = function toggleInfo () {
if (infoInterval) {
enableInfo()
} else {
disableInfo()
}
}
window.emulator.add_listener('screen-set-size-graphical', (...args) => {
console.log(...args)
})
/**
* Start information gathering, but only if the panel is visible
*/
export function startInfoMaybe () {
if (status.style.display !== 'none') {
enableInfo()
}
}
setInterval(() => {
/**
* Enable the gathering of information (and hide the little information tab)
*/
export function enableInfo () {
// Show the info thingy
status.style.display = 'block'
// We can only do the rest with an emulator
if (!window.emulator) return
// Set listeners
window.emulator.add_listener('ide-read-start', onIDEReadStart)
window.emulator.add_listener('ide-read-end', onIDEReadWriteEnd)
window.emulator.add_listener('ide-write-end', onIDEReadWriteEnd)
window.emulator.add_listener('screen-set-size-graphical', console.log)
// Set an interval
infoInterval = setInterval(() => {
const now = Date.now()
const instructionCounter = window.emulator.get_instruction_counter()
const ips = instructionCounter - lastCounter
@ -34,3 +62,24 @@ export function setupInfo () {
cpuStatus.innerHTML = Math.round(ips / deltaTime)
}, 500)
}
/**
* Disable the gathering of information (and hide the little information tab)
*/
export function disableInfo () {
// Hide the info thingy
status.style.display = 'none'
// Clear the interval
clearInterval(infoInterval)
infoInterval = null
// We can only do the rest with an emulator
if (!window.emulator) return
// Unset the listeners
window.emulator.remove_listener('ide-read-start', onIDEReadStart)
window.emulator.remove_listener('ide-read-end', onIDEReadWriteEnd)
window.emulator.remove_listener('ide-write-end', onIDEReadWriteEnd)
window.emulator.remove_listener('screen-set-size-graphical', console.log)
}

28
src/renderer/ipc.js Normal file
View file

@ -0,0 +1,28 @@
export function setupIpcListeners () {
const { windows95 } = window;
windows95.on(windows95.CONSTANTS.MACHINE_RESTART, () => {
if (!window.emulator || !window.emulator.is_running) return
window.emulator.restart()
})
windows95.on(windows95.CONSTANTS.MACHINE_CTRL_ALT_DEL, () => {
if (!window.emulator || !window.emulator.is_running) return
window.emulator.keyboard_send_scancodes([
0x1D, // ctrl
0x38, // alt
0x53, // delete
// break codes
0x1D | 0x80,
0x38 | 0x80,
0x53 | 0x80
])
})
windows95.on(windows95.CONSTANTS.SHOW_DISK_IMAGE, () => {
windows95.showDiskImage()
})
}

View file

@ -1,7 +1,8 @@
/* We're using modern esm imports here */
import { setupState } from 'es6://app-state.js'
import { setupClickListener, setupEscListener, setupCloseListener } from 'es6://listeners.js'
import { toggleButtons, setupButtons } from 'es6://buttons.js'
import { setupInfo } from 'es6://info.js'
import { startInfoMaybe } from 'es6://info.js'
setupState()
@ -9,9 +10,10 @@ setupState()
* The main method executing the VM.
*/
async function main () {
// New v86 instance
window.emulator = new V86Starter({
memory_size: 64 * 1024 * 1024,
const imageSize = await window.windows95.getDiskImageSize()
const options = {
memory_size: 128 * 1024 * 1024,
video_memory_size: 32 * 1024 * 1024,
screen_container: document.getElementById('emulator'),
bios: {
url: './bios/seabios.bin'
@ -22,21 +24,19 @@ async function main () {
hda: {
url: '../images/windows95.img',
async: true,
size: 242049024
size: imageSize
},
fda: {
buffer: window.appState.floppyFile || undefined
},
boot_order: 0x132
})
// High DPI support
if (navigator.userAgent.includes('Windows')) {
const scale = window.devicePixelRatio
window.emulator.screen_adapter.set_scale(scale, scale)
}
console.log(`Starting emulator with options`, options)
// New v86 instance
window.emulator = new V86Starter(options)
// Restore state. We can't do this right away
// and randomly chose 500ms as the appropriate
// wait time (lol)
@ -45,7 +45,7 @@ async function main () {
windows95.restoreState()
}
setupInfo()
startInfoMaybe()
window.appState.cursorCaptured = true
window.emulator.lock_mouse()

View file

@ -1,9 +1,6 @@
const fs = require('fs-extra')
const path = require('path')
const { remote } = require('electron')
const DEFAULT_PATH = path.join(__dirname, 'images/default-state.bin')
const STATE_PATH = path.join(remote.app.getPath('userData'), 'state.bin')
const { CONSTANTS } = require('./constants')
/**
* Returns the current machine's state - either what
@ -12,11 +9,9 @@ const STATE_PATH = path.join(remote.app.getPath('userData'), 'state.bin')
* @returns {ArrayBuffer}
*/
function getState () {
const statePath = fs.existsSync(STATE_PATH)
? STATE_PATH
: DEFAULT_PATH
return fs.readFileSync(statePath).buffer
if (fs.existsSync(CONSTANTS.STATE_PATH)) {
return fs.readFileSync(CONSTANTS.STATE_PATH).buffer
}
}
/**
@ -25,8 +20,8 @@ function getState () {
* @returns {Promise<void>}
*/
async function resetState () {
if (fs.existsSync(STATE_PATH)) {
return fs.remove(STATE_PATH)
if (fs.existsSync(CONSTANTS.STATE_PATH)) {
return fs.remove(CONSTANTS.STATE_PATH)
}
}
@ -43,13 +38,13 @@ async function saveState () {
window.emulator.save_state(async (error, newState) => {
if (error) {
console.log(error)
console.warn(`State: Could not save state`, error)
return
}
await fs.outputFile(STATE_PATH, Buffer.from(newState))
await fs.outputFile(CONSTANTS.STATE_PATH, Buffer.from(newState))
console.log(`Saved state to ${STATE_PATH}`)
console.log(`State: Saved state to ${CONSTANTS.STATE_PATH}`)
resolve()
})
@ -60,15 +55,21 @@ async function saveState () {
* Restores the VM's state.
*/
function restoreState () {
const state = getState()
// Nothing to do with if we don't have a state
if (!state) {
console.log(`State: No state present, not restoring.`)
}
try {
window.emulator.restore_state(getState())
window.emulator.restore_state(state)
} catch (error) {
console.log(`Could not read state file. Maybe none exists?`, error)
console.log(`State: Could not read state file. Maybe none exists?`, error)
}
}
module.exports = {
STATE_PATH,
saveState,
restoreState,
resetState,

View file

@ -0,0 +1,26 @@
const fs = require('fs-extra')
const { CONSTANTS } = require('../constants')
/**
* Get the size of the disk image
*
* @returns {number}
*/
async function getDiskImageSize () {
try {
const stats = await fs.stat(CONSTANTS.IMAGE_PATH)
if (stats) {
return stats.size
}
} catch (error) {
console.warn(`Could not determine image size`, error)
}
return CONSTANTS.IMAGE_DEFAULT_SIZE
}
module.exports = {
getDiskImageSize
}