feat/webworker: work in progress [might break]
/ test (push) Successful in 6s
Details
/ test (push) Successful in 6s
Details
This commit is contained in:
parent
0e8d173289
commit
2e56d235ed
|
@ -91,7 +91,7 @@ AFRAME.registerComponent('codemirror', {
|
||||||
|
|
||||||
// component events
|
// component events
|
||||||
DOMready: function(e){
|
DOMready: function(e){
|
||||||
this.isoterminal.emulator.read_file( this.data.file )
|
this.isoterminal.worker.postMessage.promise({event:'read_file',data: this.data.file })
|
||||||
.then( this.isoterminal.convert.Uint8ArrayToString )
|
.then( this.isoterminal.convert.Uint8ArrayToString )
|
||||||
.then( (str) => {
|
.then( (str) => {
|
||||||
this.createEditor( str )
|
this.createEditor( str )
|
||||||
|
|
|
@ -43,8 +43,8 @@ if( typeof AFRAME != 'undefined '){
|
||||||
transparent: { type:'boolean', "default":false }, // need good gpu
|
transparent: { type:'boolean', "default":false }, // need good gpu
|
||||||
xterm: { type: 'boolean', "default":true }, // use xterm.js? (=slower)
|
xterm: { type: 'boolean', "default":true }, // use xterm.js? (=slower)
|
||||||
memory: { type: 'number', "default":48 }, // VM memory (in MB)
|
memory: { type: 'number', "default":48 }, // VM memory (in MB)
|
||||||
bufferLatency:{ type: 'number', "default":200 } // bufferlatency from worker to xterm
|
bufferLatency:{ type: 'number', "default":300 }, // in ms: bufferlatency from webworker to xterm (batch-update every char to texture)
|
||||||
// (re-uploading the canvas per character is slooow)
|
canvasLatency:{ type: 'number', "default":300 } // in ms: time between canvas re-draws
|
||||||
},
|
},
|
||||||
|
|
||||||
init: function(){
|
init: function(){
|
||||||
|
@ -187,7 +187,7 @@ if( typeof AFRAME != 'undefined '){
|
||||||
jsconsole: "com/isoterminal/feat/jsconsole.js",
|
jsconsole: "com/isoterminal/feat/jsconsole.js",
|
||||||
indexhtml: "com/isoterminal/feat/index.html.js",
|
indexhtml: "com/isoterminal/feat/index.html.js",
|
||||||
indexjs: "com/isoterminal/feat/index.js.js",
|
indexjs: "com/isoterminal/feat/index.js.js",
|
||||||
//autorestore: "com/isoterminal/feat/autorestore.js",
|
autorestore: "com/isoterminal/feat/autorestore.js",
|
||||||
})
|
})
|
||||||
|
|
||||||
this.el.setAttribute("selfcontainer","")
|
this.el.setAttribute("selfcontainer","")
|
||||||
|
@ -218,7 +218,7 @@ if( typeof AFRAME != 'undefined '){
|
||||||
|
|
||||||
instance.addEventListener('window.oncreate', (e) => {
|
instance.addEventListener('window.oncreate', (e) => {
|
||||||
instance.dom.classList.add('blink')
|
instance.dom.classList.add('blink')
|
||||||
instance.setAttribute("xterm",`cols: ${this.data.cols}; rows: ${this.data.rows}`)
|
instance.setAttribute("xterm",`cols: ${this.data.cols}; rows: ${this.data.rows}; canvasLatency: ${this.data.canvasLatency}`)
|
||||||
instance.addEventListener("xterm-input", (e) => this.isoterminal.send(e.detail,0) )
|
instance.addEventListener("xterm-input", (e) => this.isoterminal.send(e.detail,0) )
|
||||||
// run iso
|
// run iso
|
||||||
let opts = {dom:instance.dom}
|
let opts = {dom:instance.dom}
|
||||||
|
|
|
@ -126,30 +126,52 @@ ISOTerminal.prototype.start = function(opts){
|
||||||
autostart: true,
|
autostart: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the WebWorker (which runs v86)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
this.worker = new Worker("com/isoterminal/worker.js");
|
this.worker = new Worker("com/isoterminal/worker.js");
|
||||||
this.worker.onmessage = (e) => {
|
this.worker.onmessage = (e) => {
|
||||||
|
const xr = this.instance.sceneEl.renderer.xr
|
||||||
const {event,data} = e.data
|
const {event,data} = e.data
|
||||||
this.emit(event,data,"worker")
|
const cb = (event,data) => () => {
|
||||||
|
if( data.promiseId ){
|
||||||
|
this.workerPromise.resolver(data) // forward to promise resolver
|
||||||
|
}else this.emit(event,data,"worker") // forward event to world
|
||||||
|
|
||||||
|
}
|
||||||
|
// don't let workers cause framerate dropping
|
||||||
|
if( xr.isPresenting ){
|
||||||
|
xr.getSession().requestAnimationFrame(cb(event,data))
|
||||||
|
}else{
|
||||||
|
window.requestAnimationFrame(cb(event,data))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//this.term = new window.Terminal({
|
/*
|
||||||
// logLevel:"off",
|
* postMessage.promise basically performs this.worker.postMessage
|
||||||
// rows: 50,
|
* in a promise way (to easily retrieve async output)
|
||||||
// cols: 110
|
*/
|
||||||
//})
|
|
||||||
//this.term.open( this.instance.dom )
|
|
||||||
//this.term.onData( (data) => {
|
|
||||||
// for(let i = 0; i < data.length; i++){
|
|
||||||
// this.worker.postMessage({event:"serial0-input", data: data.charCodeAt(i) })
|
|
||||||
// }
|
|
||||||
//})
|
|
||||||
|
|
||||||
//this.instance.addEventListener('serial-output-byte', (e) => {
|
this.worker.postMessage.promise = function(data){
|
||||||
// const byte = e.detail
|
if( typeof data != 'object' ) data = {data}
|
||||||
// this.term.write(byte)
|
this.resolvers = this.resolvers || {}
|
||||||
//})
|
this.id = this.id == undefined ? 0 : this.id
|
||||||
|
data.id = this.id++
|
||||||
|
// Send id and task to WebWorker
|
||||||
|
this.worker.postMessage(data)
|
||||||
|
return new Promise(resolve => this.resolvers[data.id] = resolve);
|
||||||
|
}.bind(this.worker.postMessage)
|
||||||
|
|
||||||
this.emit('runISO',opts)
|
this.worker.postMessage.promise.resolver = function(data){
|
||||||
|
if( !data || !data.promiseId ) throw 'promiseId not given'
|
||||||
|
this.resolvers[ data.promiseId ](data);
|
||||||
|
delete this.resolvers[ data.promiseId ]; // Prevent memory leak
|
||||||
|
}.bind(this.worker.postMessage)
|
||||||
|
|
||||||
|
|
||||||
|
this.emit('runISO',{...opts, bufferLatency: this.opts.bufferLatency })
|
||||||
const loading = [
|
const loading = [
|
||||||
'loading quantum bits and bytes',
|
'loading quantum bits and bytes',
|
||||||
'preparing quantum flux capacitors',
|
'preparing quantum flux capacitors',
|
||||||
|
@ -194,40 +216,34 @@ ISOTerminal.prototype.start = function(opts){
|
||||||
//}
|
//}
|
||||||
|
|
||||||
let line = ''
|
let line = ''
|
||||||
let ready = false
|
this.ready = false
|
||||||
this.addEventListener(`serial0-output-byte`, async (e) => {
|
|
||||||
const byte = e.detail
|
|
||||||
//this.emit("serial-output-byte",byte) // send to xterm
|
|
||||||
this.bufferOutput(`serial-output-byte`, byte)
|
|
||||||
var chr = String.fromCharCode(byte);
|
|
||||||
if(chr < " " && chr !== "\n" && chr !== "\t" || chr > "~") return
|
|
||||||
|
|
||||||
if(chr === "\n")
|
this.addEventListener(`serial0-output-string`, async (e) => {
|
||||||
{
|
const str = e.detail
|
||||||
var new_line = line;
|
|
||||||
line = "";
|
|
||||||
} else if(chr >= " " && chr <= "~"){ line += chr }
|
|
||||||
|
|
||||||
if( !ready && line.match(/^(\/ #|~%|\[.*\]>)/) ){
|
// lets scan for a prompt so we can send a 'ready' event to the world
|
||||||
|
if( !this.ready && str.match(/\n(\/ #|~%|\[.*\]>)/) ){
|
||||||
this.emit('postReady',{})
|
this.emit('postReady',{})
|
||||||
|
this.ready = true
|
||||||
setTimeout( () => this.emit('ready',{}), 500 )
|
setTimeout( () => this.emit('ready',{}), 500 )
|
||||||
ready = true
|
|
||||||
}
|
}
|
||||||
});
|
if( this.ready ) this.emit('serial-output-string', e.detail )
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ISOTerminal.prototype.bufferOutput = function(type,byte){
|
ISOTerminal.prototype.bufferOutput = function(byte,cb,latency){
|
||||||
this.buffer = this.buffer || {str:""}
|
const resetBuffer = () => ({str:""})
|
||||||
if( this.buffer.id ) this.buffer.str += String.fromCharCode(byte)
|
this.buffer = this.buffer || resetBuffer()
|
||||||
else{
|
this.buffer.str += String.fromCharCode(byte)
|
||||||
this.emit(type, byte ) // leading call
|
if( !this.buffer.id ){
|
||||||
this.buffer.id = setTimeout( () => { // trailing calls
|
cb(this.buffer.str) // send out leading call
|
||||||
if( this.buffer.str ){
|
this.buffer = resetBuffer()
|
||||||
this.emit('serial-output-string', this.buffer.str )
|
this.buffer.id = setTimeout( () => { // accumulate succesive calls
|
||||||
}
|
if( this.buffer.str ) cb(this.buffer.str)
|
||||||
this.buffer = {str:""}
|
this.buffer = resetBuffer()
|
||||||
}, this.opts.bufferLatency || 250)
|
}, this.latency || 250)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,23 @@
|
||||||
ISOTerminal.addEventListener('emulator-started', function(e){
|
if( typeof emulator != 'undefined' ){
|
||||||
return console.log("TODO: autorestore.js")
|
// inside worker-thread
|
||||||
this.autorestore(e)
|
|
||||||
})
|
|
||||||
|
|
||||||
ISOTerminal.prototype.autorestore = async function(e){
|
this['emulator.restore_state'] = async function(){
|
||||||
|
await emulator.restore_state.apply(emulator, arguments[0])
|
||||||
|
this.postMessage({event:"state_restored",data:false})
|
||||||
|
}
|
||||||
|
this['emulator.save_state'] = async function(){
|
||||||
|
let state = await emulator.save_state.apply(emulator, arguments[0])
|
||||||
|
this.postMessage({event:"state_saved",data:state})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}else{
|
||||||
|
// inside browser-thread
|
||||||
|
ISOTerminal.addEventListener('emulator-started', function(e){
|
||||||
|
this.autorestore(e)
|
||||||
|
})
|
||||||
|
|
||||||
|
ISOTerminal.prototype.autorestore = async function(e){
|
||||||
|
|
||||||
localforage.setDriver([
|
localforage.setDriver([
|
||||||
localforage.INDEXEDDB,
|
localforage.INDEXEDDB,
|
||||||
|
@ -15,7 +29,8 @@ ISOTerminal.prototype.autorestore = async function(e){
|
||||||
if( stateBase64 && !err && confirm('continue last session?') ){
|
if( stateBase64 && !err && confirm('continue last session?') ){
|
||||||
this.noboot = true // see feat/boot.js
|
this.noboot = true // see feat/boot.js
|
||||||
state = this.convert.base64ToArrayBuffer( stateBase64 )
|
state = this.convert.base64ToArrayBuffer( stateBase64 )
|
||||||
this.emulator.restore_state(state)
|
|
||||||
|
this.addEventListener('state_restored', function(){
|
||||||
this.emit('postReady',e)
|
this.emit('postReady',e)
|
||||||
setTimeout( () => {
|
setTimeout( () => {
|
||||||
this.emit('ready',e)
|
this.emit('ready',e)
|
||||||
|
@ -33,15 +48,22 @@ ISOTerminal.prototype.autorestore = async function(e){
|
||||||
.catch( console.error )
|
.catch( console.error )
|
||||||
|
|
||||||
}, 500 )
|
}, 500 )
|
||||||
|
})
|
||||||
|
|
||||||
|
this.worker.postMessage({event:'emulator.restore_state',data:state})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.save = async () => {
|
this.save = async () => {
|
||||||
const state = await this.emulator.save_state()
|
const state = await this.worker.postMessage({event:"save_state",data:false})
|
||||||
console.log( String(this.convert.arrayBufferToBase64(state)).substr(0,5) )
|
console.log( String(this.convert.arrayBufferToBase64(state)).substr(0,5) )
|
||||||
localforage.setItem("state", this.convert.arrayBufferToBase64(state) )
|
localforage.setItem("state", this.convert.arrayBufferToBase64(state) )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.addEventListener('state_saved', function(data){
|
||||||
|
debugger
|
||||||
|
})
|
||||||
|
|
||||||
window.addEventListener("beforeunload", function (e) {
|
window.addEventListener("beforeunload", function (e) {
|
||||||
var confirmationMessage = "Sure you want to leave?\nTIP: enter 'save' to continue this session later";
|
var confirmationMessage = "Sure you want to leave?\nTIP: enter 'save' to continue this session later";
|
||||||
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
|
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
|
||||||
|
@ -49,5 +71,6 @@ ISOTerminal.prototype.autorestore = async function(e){
|
||||||
});
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Binary file not shown.
|
@ -40,15 +40,24 @@ this.runISO = function(opts){
|
||||||
// event forwarding
|
// event forwarding
|
||||||
|
|
||||||
emulator.add_listener("serial0-output-byte", function(byte){
|
emulator.add_listener("serial0-output-byte", function(byte){
|
||||||
this.postMessage({event:"serial0-output-byte",data:byte});
|
ISOTerminal.prototype.bufferOutput(byte, (str) => { // we buffer to prevent framerate dropping
|
||||||
|
if( !str ) return
|
||||||
|
this.postMessage({event:"serial0-output-string",data:str});
|
||||||
|
}, opts.bufferLatency )
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
emulator.add_listener("serial1-output-byte", function(byte){
|
emulator.add_listener("serial1-output-byte", function(byte){
|
||||||
this.postMessage({event:"serial1-output-byte",data:byte});
|
ISOTerminal.prototype.bufferOutput(byte, (str) => { // we buffer to prevent framerate dropping
|
||||||
|
if( !str ) return
|
||||||
|
this.postMessage({event:"serial1-output-string",data:str});
|
||||||
|
}, opts.bufferLatency )
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
emulator.add_listener("serial2-output-byte", function(byte){
|
emulator.add_listener("serial2-output-byte", function(byte){
|
||||||
this.postMessage({event:"serial2-output-byte",data:byte});
|
ISOTerminal.prototype.bufferOutput(byte, (str) => { // we buffer to prevent framerate dropping
|
||||||
|
if( !str ) return
|
||||||
|
this.postMessage({event:"serial2-output-string",data:str});
|
||||||
|
}, opts.bufferLatency )
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
emulator.add_listener("emulator-started", function(){
|
emulator.add_listener("emulator-started", function(){
|
||||||
|
@ -73,6 +82,7 @@ this.runISO = function(opts){
|
||||||
|
|
||||||
importScripts("feat/javascript.js")
|
importScripts("feat/javascript.js")
|
||||||
importScripts("feat/index.html.js")
|
importScripts("feat/index.html.js")
|
||||||
|
importScripts("feat/autorestore.js")
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* forward events/functions so non-worker world can reach them
|
* forward events/functions so non-worker world can reach them
|
||||||
|
|
15
com/xterm.js
15
com/xterm.js
|
@ -92,14 +92,9 @@ const TERMINAL_THEME = {
|
||||||
|
|
||||||
AFRAME.registerComponent('xterm', {
|
AFRAME.registerComponent('xterm', {
|
||||||
schema: Object.assign({
|
schema: Object.assign({
|
||||||
cols: {
|
cols: { type: 'number', default: 110, },
|
||||||
type: 'number',
|
rows: { type: 'number', default: Math.floor( (window.innerHeight * 0.7 ) * 0.054 ) },
|
||||||
default: 110,
|
canvasLatency:{ type:'number', default: 200 }
|
||||||
},
|
|
||||||
rows: {
|
|
||||||
type: 'number',
|
|
||||||
default: Math.floor( (window.innerHeight * 0.7 ) * 0.054 )
|
|
||||||
},
|
|
||||||
}, TERMINAL_THEME),
|
}, TERMINAL_THEME),
|
||||||
|
|
||||||
write: function(message) {
|
write: function(message) {
|
||||||
|
@ -139,6 +134,7 @@ AFRAME.registerComponent('xterm', {
|
||||||
}, {})
|
}, {})
|
||||||
|
|
||||||
const term = this.term = new Terminal({
|
const term = this.term = new Terminal({
|
||||||
|
logLevel:"off",
|
||||||
theme: theme,
|
theme: theme,
|
||||||
allowTransparency: true,
|
allowTransparency: true,
|
||||||
cursorBlink: true,
|
cursorBlink: true,
|
||||||
|
@ -157,7 +153,7 @@ AFRAME.registerComponent('xterm', {
|
||||||
//this.term._core.viewport._innerRefresh()
|
//this.term._core.viewport._innerRefresh()
|
||||||
this.term._core.renderer._renderDebouncer._innerRefresh()
|
this.term._core.renderer._renderDebouncer._innerRefresh()
|
||||||
}
|
}
|
||||||
},150)
|
}, this.data.canvasLatency)
|
||||||
|
|
||||||
this.term.open(terminalElement)
|
this.term.open(terminalElement)
|
||||||
this.term.focus()
|
this.term.focus()
|
||||||
|
@ -191,6 +187,7 @@ AFRAME.registerComponent('xterm', {
|
||||||
const material = this.el.planeText.getObject3D('mesh').material
|
const material = this.el.planeText.getObject3D('mesh').material
|
||||||
if (!material.map ) return
|
if (!material.map ) return
|
||||||
if( this.cursorCanvas ) this.canvasContext.drawImage(this.cursorCanvas, 0,0)
|
if( this.cursorCanvas ) this.canvasContext.drawImage(this.cursorCanvas, 0,0)
|
||||||
|
else console.log("no cursorCanvas")
|
||||||
material.map.needsUpdate = true
|
material.map.needsUpdate = true
|
||||||
//material.needsUpdate = true
|
//material.needsUpdate = true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue