added remotestorage
This commit is contained in:
parent
c79af592e6
commit
6a4342f1d9
7 changed files with 477 additions and 47 deletions
|
|
@ -304,15 +304,17 @@ if( typeof AFRAME != 'undefined '){
|
|||
remotekeyboard: "com/isoterminal/feat/remotekeyboard.js",
|
||||
indexhtml: "com/isoterminal/feat/index.html.js",
|
||||
indexjs: "com/isoterminal/feat/index.js.js",
|
||||
autorestore: "com/isoterminal/feat/autorestore.js",
|
||||
pastedropFeat: "com/isoterminal/feat/pastedrop.js",
|
||||
httpfs: "com/isoterminal/feat/httpfs.js",
|
||||
autorestore: "com/isoterminal/feat/autorestore.js",
|
||||
}
|
||||
if( this.data.emulator == 'fbterm' ){
|
||||
features['fbtermjs'] = "com/isoterminal/term.js"
|
||||
features['fbterm'] = "com/isoterminal/feat/term.js"
|
||||
}
|
||||
await AFRAME.utils.require(features)
|
||||
// this one extends autorestore.js
|
||||
await AFRAME.utils.require({remotestorage: "com/isoterminal/feat/remotestorage.js"})
|
||||
|
||||
this.el.setAttribute("selfcontainer","")
|
||||
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ ISOTerminal.prototype.startVM = function(opts){
|
|||
this.v86opts = opts
|
||||
|
||||
this.addEventListener('emulator-started', async (e) => {
|
||||
if( this.boot.fromImage ) return this.emit('serial-output-string', "\r[!] downloading session...please wait\n\r[!] this could take a while depending on your connection..\n\r")
|
||||
|
||||
let line = ''
|
||||
this.ready = false
|
||||
|
|
@ -278,12 +279,17 @@ ISOTerminal.prototype.startVM = function(opts){
|
|||
}
|
||||
|
||||
ISOTerminal.prototype.bootISO = function(){
|
||||
const getImage = (str) => decodeURIComponent(
|
||||
str.match(/\&img=/) ? str.replace(/.*img=/,'').replace(/\&.*/,'') : ''
|
||||
)
|
||||
let msglib = this.getLoaderMsg()
|
||||
this.emit('status',msglib.loadmsg)
|
||||
let msg = "\n\r" + msglib.empowermsg + msglib.text_color + msglib.loadmsg + msglib.text_reset
|
||||
this.emit('serial-output-string', msg)
|
||||
this.emit('runISO',{...this.v86opts, bufferLatency: this.opts.bufferLatency })
|
||||
|
||||
if( getImage(this.boot.hash) ){
|
||||
this.boot.fromImage = true
|
||||
}
|
||||
this.emit('runISO',{...this.v86opts, bufferLatency: this.opts.bufferLatency, img: getImage(this.boot.hash) })
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,16 @@
|
|||
// this is restoring state to/from the v86 emulator
|
||||
// however instead of passing the huge blob between webworker/browser
|
||||
// we transfer it via localforage as a base64 string
|
||||
|
||||
if( typeof emulator != 'undefined' ){
|
||||
// inside worker-thread
|
||||
importScripts("localforage.js") // we don't instance it again here (just use its functions)
|
||||
|
||||
this.restore_state = async function(data){
|
||||
// fastforward instance state
|
||||
this.opts.muteUntilPrompt = false
|
||||
this.ready = true
|
||||
|
||||
return new Promise( (resolve,reject) => {
|
||||
localforage.getItem("state", async (err,stateBase64) => {
|
||||
if( stateBase64 && !err ){
|
||||
|
|
@ -15,15 +23,20 @@ if( typeof emulator != 'undefined' ){
|
|||
})
|
||||
}
|
||||
this.save_state = async function(){
|
||||
console.log("saving session")
|
||||
let state = await emulator.save_state()
|
||||
localforage.setDriver([
|
||||
localforage.INDEXEDDB,
|
||||
localforage.WEBSQL,
|
||||
localforage.LOCALSTORAGE
|
||||
]).then( () => {
|
||||
localforage.setItem("state", ISOTerminal.prototype.convert.arrayBufferToBase64(state) )
|
||||
console.log("state saved")
|
||||
return new Promise( async (resolve,reject ) => {
|
||||
console.log("saving session")
|
||||
let state = await emulator.save_state()
|
||||
localforage.setDriver([
|
||||
localforage.INDEXEDDB,
|
||||
localforage.WEBSQL,
|
||||
localforage.LOCALSTORAGE
|
||||
])
|
||||
.then( () => {
|
||||
localforage.setItem("state", ISOTerminal.prototype.convert.arrayBufferToBase64(state) )
|
||||
console.log("state saved")
|
||||
resolve()
|
||||
})
|
||||
.catch( reject )
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -32,42 +45,44 @@ if( typeof emulator != 'undefined' ){
|
|||
// inside browser-thread
|
||||
ISOTerminal.addEventListener('emulator-started', function(e){
|
||||
this.autorestore(e)
|
||||
this.emit("autorestore-installed")
|
||||
})
|
||||
|
||||
ISOTerminal.prototype.autorestore = async function(e){
|
||||
ISOTerminal.prototype.restore = async function(e){
|
||||
|
||||
localforage.setDriver([
|
||||
localforage.INDEXEDDB,
|
||||
localforage.WEBSQL,
|
||||
localforage.LOCALSTORAGE
|
||||
]).then( () => {
|
||||
const onGetItem = (err,stateBase64) => {
|
||||
const askConfirm = () => {
|
||||
if( window.localStorage.getItem("restorestate") == "true" ) return true
|
||||
try{
|
||||
const scene = document.querySelector('a-scene');
|
||||
if( scene.is('ar-mode') ) scene.exitAR()
|
||||
if( scene.is('vr-mode') ) scene.exitVR()
|
||||
}catch(e){}
|
||||
return confirm( "Continue old session?" )
|
||||
}
|
||||
|
||||
localforage.getItem("state", async (err,stateBase64) => {
|
||||
const askConfirm = () => {
|
||||
if( window.localStorage.getItem("restorestate") == "true" ) return true
|
||||
try{
|
||||
const scene = document.querySelector('a-scene');
|
||||
if( scene.is('ar-mode') ) scene.exitAR()
|
||||
if( scene.is('vr-mode') ) scene.exitVR()
|
||||
}catch(e){}
|
||||
return confirm('continue last session?')
|
||||
}
|
||||
if( stateBase64 && !err && document.location.hash.length < 2 && askConfirm() ){
|
||||
this.noboot = true // see feat/boot.js
|
||||
try{
|
||||
await this.worker.restore_state()
|
||||
if( stateBase64 && !err && document.location.hash.length < 2 && askConfirm() ){
|
||||
this.noboot = true // see feat/boot.js
|
||||
try{
|
||||
this.worker.restore_state()
|
||||
.then( () => {
|
||||
// simulate / fastforward boot events
|
||||
this.postBoot( () => {
|
||||
this.send("l\n")
|
||||
this.send("hook wakeup\n")
|
||||
// force redraw terminal issue
|
||||
this.send("l")
|
||||
setTimeout( () => this.send("l"), 200 )
|
||||
//this.send("12")
|
||||
this.emit("exec",["source /etc/profile.sh; hook wakeup\n"])
|
||||
this.emit("restored")
|
||||
})
|
||||
}catch(e){ console.error(e) }
|
||||
}
|
||||
})
|
||||
|
||||
this.save = async () => {
|
||||
await this.worker.save_state()
|
||||
})
|
||||
}catch(e){ console.error(e) }
|
||||
}
|
||||
}
|
||||
|
||||
const doRestore = () => {
|
||||
|
||||
localforage.getItem("state", (err,stateBase64) => onGetItem(err,stateBase64) )
|
||||
|
||||
window.addEventListener("beforeunload", function (e) {
|
||||
var confirmationMessage = "Sure you want to leave?\nTIP: enter 'save' to continue this session later";
|
||||
|
|
@ -75,7 +90,17 @@ if( typeof emulator != 'undefined' ){
|
|||
return confirmationMessage; //Webkit, Safari, Chrome
|
||||
});
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
localforage.setDriver([
|
||||
localforage.INDEXEDDB,
|
||||
localforage.WEBSQL,
|
||||
localforage.LOCALSTORAGE
|
||||
])
|
||||
.then( () => doRestore() )
|
||||
|
||||
}
|
||||
|
||||
ISOTerminal.prototype.autorestore = ISOTerminal.prototype.restore // alias to launch during boot
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
ISOTerminal.addEventListener('ready', function(e){
|
||||
setTimeout( () => this.boot(), 50 ) // because of autorestore.js
|
||||
setTimeout( () => this.boot(), 50 ) // allow other features/plugins to settle first (autorestore.js e.g.)
|
||||
})
|
||||
|
||||
ISOTerminal.prototype.bootMenu = function(e){
|
||||
|
|
@ -17,7 +17,7 @@ ISOTerminal.prototype.bootMenu = function(e){
|
|||
|
||||
}else{ // autoboot
|
||||
if( this.term ){
|
||||
this.term.handler( e.detail.bootMenu || e.detail.bootMenuURL )
|
||||
this.term.handler( String(e.detail.bootMenu || e.detail.bootMenuURL).charAt(0) )
|
||||
this.term.handler("\n")
|
||||
}
|
||||
}
|
||||
|
|
@ -33,10 +33,17 @@ ISOTerminal.prototype.boot = async function(e){
|
|||
'export BROWSER=1',
|
||||
]
|
||||
for ( let i in document.location ){
|
||||
if( typeof document.location[i] == 'string' ){
|
||||
if( typeof document.location[i] == 'string' && !String(i).match(/(hash|search)/) ){
|
||||
env.push( 'export '+String(i).toUpperCase()+'="'+decodeURIComponent( document.location[i]+'"') )
|
||||
}
|
||||
}
|
||||
|
||||
// we export the cached hash/query (because they might be gone due to remotestorage plugin)
|
||||
if( this.boot.hash.charAt(2) == '&' ){ // strip bootoption
|
||||
this.boot.hashExBoot = `#` + this.boot.hash.substr(3)
|
||||
}
|
||||
env.push( 'export HASH="'+decodeURIComponent( this.boot.hashExBoot || this.boot.hash ) +'"' )
|
||||
env.push( 'export QUERY="'+decodeURIComponent( this.boot.query ) +'"' )
|
||||
await this.worker.create_file("profile.browser", this.convert.toUint8Array( env.join('\n') ) )
|
||||
|
||||
if( this.serial_input == 0 ){
|
||||
|
|
@ -47,8 +54,12 @@ ISOTerminal.prototype.boot = async function(e){
|
|||
|
||||
}
|
||||
|
||||
// here REPL's can be defined
|
||||
ISOTerminal.prototype.boot.fromImage = false
|
||||
ISOTerminal.prototype.boot.menu = []
|
||||
ISOTerminal.prototype.boot.hash = document.location.hash
|
||||
ISOTerminal.prototype.boot.query = document.location.search
|
||||
|
||||
// here REPL's can be defined
|
||||
|
||||
// REPL: iso
|
||||
if( typeof window.PromiseWorker != 'undefined' ){ // if xrsh v86 is able to run in in worker
|
||||
|
|
|
|||
365
com/isoterminal/feat/remotestorage.js
Normal file
365
com/isoterminal/feat/remotestorage.js
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
/* Remote storage feature
|
||||
*
|
||||
* NOTE: this feature extends the localstorage functions.
|
||||
* this file can be excluded without crippling the
|
||||
* core localstorage mechanism.
|
||||
*/
|
||||
|
||||
// see https://remotestorage.io/rs.js/docs/data-modules/
|
||||
ISOTerminal.prototype.remoteStorageModule = {
|
||||
name: 'xrsh',
|
||||
builder: function(privateClient, publicClient) {
|
||||
return {
|
||||
exports: {
|
||||
add: function(data,opts) {
|
||||
if( !data || !opts.filename || !opts.mimetype) throw 'webxr.add() needs filedata + filename + mimetype'
|
||||
const client = opts.client = opts.public ? publicClient : privateClient;
|
||||
return client.storeFile(opts.mimetype, opts.filename,data)
|
||||
},
|
||||
|
||||
getListing: function(a,opts){
|
||||
opts = opts || {}
|
||||
const client = opts.public ? publicClient : privateClient;
|
||||
return client.getListing(a)
|
||||
},
|
||||
|
||||
getFile: function(file,opts){
|
||||
opts = opts || {}
|
||||
const client = opts.public ? publicClient : privateClient;
|
||||
return client.getFile(file)
|
||||
},
|
||||
|
||||
remove: function(file,opts){
|
||||
opts = opts || {}
|
||||
const client = opts.public ? publicClient : privateClient;
|
||||
return client.remove(file)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// this is the HTML which we append to the remotestorage widget:
|
||||
// https://remotestorage.io/rs.js/docs/getting-started/connect-widget.html
|
||||
const _rs_widget_html = `
|
||||
<div class="form" id="remote">
|
||||
<select class="remote" id="states"></select>
|
||||
<button id="save">save</button>
|
||||
|
||||
<a class="btn remote" href="https://inspektor.5apps.com/?path=xrsh%2F" style="background:#888" target="_blank">filemanager</a>
|
||||
<div id="result"></div>
|
||||
</div>
|
||||
<div class="form" id="local" style="position:relative">
|
||||
<hr>
|
||||
<div class="header">WebBrowser session:</div>
|
||||
<div style="text-align:right">
|
||||
<button id="saveLocal">save</button>
|
||||
<button id="restoreLocal">restore</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- disabled for now -->
|
||||
<div class="form" id="local" style="position:relative; display:none">
|
||||
<hr>
|
||||
<div class="header">File session:</div>
|
||||
<div style="text-align:right">
|
||||
<button id="saveLocalFile">save file</button>
|
||||
<button id="restoreLocalFile">import file</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style type="text/css">
|
||||
#remotestorage-widget{
|
||||
position:fixed;
|
||||
top:0;
|
||||
right:0;
|
||||
}
|
||||
#remotestorage-widget h1,
|
||||
#remotestorage-widget h2,
|
||||
#remotestorage-widget h3,
|
||||
#remotestorage-widget h4,
|
||||
#remotestorage-widget h5{
|
||||
color:#222;
|
||||
}
|
||||
#remotestorage-widget .rs-widget{
|
||||
margin:25px;
|
||||
}
|
||||
#remotestorage-widget .rs-closed .form{
|
||||
display:none !important;
|
||||
}
|
||||
#remotestorage-widget .form select#states{
|
||||
padding: 5px;
|
||||
margin-top: 10px;
|
||||
margin-right: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
#remotestorage-widget .form #result{
|
||||
padding-top:10px;
|
||||
}
|
||||
#remotestorage-widget .form select,
|
||||
#remotestorage-widget .form button,
|
||||
#remotestorage-widget .form a{
|
||||
height:35px;
|
||||
margin-bottom:0;
|
||||
}
|
||||
#remotestorage-widget *{
|
||||
font-size:15px;
|
||||
}
|
||||
#remotestorage-widget div.header{
|
||||
position:absolute;
|
||||
display:inline;
|
||||
top:15px;
|
||||
left:0;
|
||||
font-weight:bold;
|
||||
}
|
||||
#remotestorage-widget .form .btn {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
display: inline-block;
|
||||
line-height: 15px;
|
||||
}
|
||||
#remotestorage-widget .form{
|
||||
margin-top:10px;
|
||||
}
|
||||
#remotestorage-widget .btn:hover,
|
||||
#remotestorage-widget button:hover {
|
||||
background:#CCC;
|
||||
}
|
||||
</style>
|
||||
`
|
||||
|
||||
const widgetForm = function(opts){
|
||||
let el = document.querySelector("#remotestorage-widget select#states")
|
||||
const $widget = document.querySelector("#remotestorage-widget .rs-widget")
|
||||
const $result = document.querySelector("#remotestorage-widget #result")
|
||||
if( !el ){
|
||||
|
||||
let div = document.createElement('div')
|
||||
div.innerHTML = _rs_widget_html
|
||||
$widget.appendChild(div)
|
||||
$widget.querySelector("h3").innerText = "Click here to connect your storage"
|
||||
|
||||
el = $widget.querySelector("select#states")
|
||||
el.addEventListener('change', () => {
|
||||
if( el.options.selectedIndex == 0 ) return; // ignore default option
|
||||
this.remoteStorage.widget.filename = el.value
|
||||
opts.status = "loading..."
|
||||
$widget.classList.add(["blink"])
|
||||
this.remoteStorage.xrsh.getFile(el.value)
|
||||
.then( (data,err) => {
|
||||
this.restore({remotestorage:true, data:data.data})
|
||||
})
|
||||
})
|
||||
|
||||
this.setupStorageListeners($widget,opts)
|
||||
}
|
||||
|
||||
this.updateStorageForm(el,$widget,$result,opts)
|
||||
}
|
||||
|
||||
ISOTerminal.prototype.remoteStorageWidget = function(){
|
||||
if( this.remoteStorageWidget.installed ) return // only do once
|
||||
let apis = {
|
||||
//dropbox: "ce876ce",
|
||||
//googledrive: "c3983c3"
|
||||
}
|
||||
const modules = [ this.remoteStorageModule ]
|
||||
const remoteStorage = this.remoteStorage = new RemoteStorage({logging: true, modules })
|
||||
remoteStorage.setApiKeys(apis)
|
||||
|
||||
remoteStorage.on('not-connected', (e) => {
|
||||
this.remoteStorage.connected = false
|
||||
this.remoteStorage.widget.form({show:false})
|
||||
})
|
||||
remoteStorage.on('ready', (e) => { })
|
||||
remoteStorage.on('connected', (e) => {
|
||||
this.remoteStorage.connected = true
|
||||
this.remoteStorage.widget.form({update:true,show:true})
|
||||
})
|
||||
|
||||
remoteStorage.access.claim( `xrsh`, 'rw'); // our data dir
|
||||
remoteStorage.caching.enable( `/xrsh/` ) // local-first, remotestorage-second
|
||||
remoteStorage.caching.enable( `/public/xrsh/` ) // local-first, remotestorage-second
|
||||
|
||||
// create widget
|
||||
let opts = {}
|
||||
opts.modalBackdrop = false
|
||||
opts.leaveOpen = false
|
||||
const widget = remoteStorage.widget = new window.Widget(remoteStorage, opts)
|
||||
widget.attach();
|
||||
widget.form = widgetForm.bind(this)
|
||||
|
||||
this.remoteStorageWidget.installed = true
|
||||
}
|
||||
|
||||
ISOTerminal.prototype.setupStorageListeners = function($widget,opts){
|
||||
|
||||
this.addEventListener("ready", () => {
|
||||
opts.loading = false
|
||||
opts.status = "session loaded"
|
||||
})
|
||||
|
||||
// setup events
|
||||
$widget.querySelector("button#save").addEventListener("click", () => {
|
||||
this.save({remotestorage:true})
|
||||
})
|
||||
$widget.querySelector("button#saveLocal").addEventListener("click", async () => {
|
||||
if( confirm("save current session?") ){
|
||||
$widget.classList.add(['blink'])
|
||||
await this.worker.save_state()
|
||||
$widget.classList.remove(['blink'])
|
||||
alert("succesfully saved session")
|
||||
}
|
||||
})
|
||||
$widget.querySelector("button#restoreLocal").addEventListener("click", async () => {
|
||||
this.restore({localstorage:true})
|
||||
})
|
||||
$widget.querySelector("button#saveLocalFile").addEventListener("click", () => {
|
||||
alert("saveFile")
|
||||
})
|
||||
$widget.querySelector("button#restoreLocalFile").addEventListener("click", () => {
|
||||
alert("saveFile")
|
||||
})
|
||||
$widget.addEventListener("click", () => this.remoteStorage.widget.open() )
|
||||
this.addEventListener("restored", () => this.remoteStorage.widget.form({loading:false, status:"session restored"}) )
|
||||
}
|
||||
|
||||
ISOTerminal.prototype.updateStorageForm = function(el,$widget,$result,opts){
|
||||
|
||||
if( typeof opts.show != 'undefined' ){
|
||||
$widget.querySelector('.form#remote').style.display = opts.show ? 'block' : 'none'
|
||||
}
|
||||
|
||||
if( typeof opts.status != 'undefined'){
|
||||
$result.innerText = opts.status
|
||||
}
|
||||
|
||||
if( opts.public ){
|
||||
const link = this.remoteStorage.remote.href + '/public/xrsh/' + this.remoteStorage.widget.filename
|
||||
const linkWebView = document.location.href.replace(/(\?|#).*/,'') + `#1&img=${link}`
|
||||
$result.innerHTML += `<br><a class="btn" href="${linkWebView}" target="_blank">public weblink</a>`
|
||||
}
|
||||
|
||||
if( typeof opts.loading != 'undefined' ){
|
||||
$widget.classList[ opts.loading ? 'add' : 'remove' ](["blink"])
|
||||
}
|
||||
|
||||
if( opts.update ){
|
||||
|
||||
const createOption = (opt) => {
|
||||
let option = document.createElement("option")
|
||||
option.value = opt.value
|
||||
option.innerText = opt.name || opt.value
|
||||
el.appendChild(option)
|
||||
}
|
||||
|
||||
el.innerHTML = ''
|
||||
createOption({value:"-- snapshots --"})
|
||||
this.remoteStorage.xrsh.getListing()
|
||||
.then( (data,err) => {
|
||||
for( let file in data ){
|
||||
createOption({value:file})
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const requireFiles = () => AFRAME.utils.require({remotestorageWidget:"assets/aframe-remotestorage.min.js"})
|
||||
const getForage = () => localforage.setDriver([
|
||||
localforage.INDEXEDDB,
|
||||
localforage.WEBSQL,
|
||||
localforage.LOCALSTORAGE
|
||||
])
|
||||
|
||||
// we extend the autorestore feature at the init-event
|
||||
ISOTerminal.addEventListener('init', function(e){
|
||||
|
||||
const decorateSave = () => {
|
||||
|
||||
let localSave = this.save
|
||||
|
||||
this.save = async (opts) => {
|
||||
requireFiles()
|
||||
.then( getForage )
|
||||
.then( async () => {
|
||||
|
||||
if( opts.localstorage ){
|
||||
this.save.localstorage(opts) // default behaviour
|
||||
}
|
||||
|
||||
this.remoteStorageWidget()
|
||||
|
||||
if( opts.remotestorage ){
|
||||
this.remoteStorage.widget.open() // force open dialog
|
||||
|
||||
let filename = String(this.remoteStorage.widget.filename || "snapshot").replace(/\.bin/,'')
|
||||
filename = prompt("please name your snapshot:", filename )
|
||||
filename = filename.replace(/\.bin*/,'') + '.bin'
|
||||
|
||||
// make it public or not (disabled for now as it does not work flawlessly)
|
||||
const public = false // confirm('create a public link?')
|
||||
this.remoteStorage.widget.filename = filename
|
||||
|
||||
this.remoteStorage.widget.form({loading:true,status: "saving.."})
|
||||
|
||||
await this.worker.save_state()
|
||||
localforage.getItem("state", async (err,stateBase64) => {
|
||||
this.remoteStorage.xrsh.add( stateBase64, {filename, mimetype: 'application/x-v86-base64', public})
|
||||
.then( () => {
|
||||
console.log("saved to remotestorage")
|
||||
setTimeout(
|
||||
() => this.remoteStorage.widget.form({update:true, loading:false, status:"saved succesfully", public})
|
||||
,500 )
|
||||
})
|
||||
.catch( console.error )
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
this.save.localstorage = localSave
|
||||
}
|
||||
|
||||
const decorateRestore = () => {
|
||||
|
||||
let localRestore = this.restore
|
||||
|
||||
this.restore = async (opts) => {
|
||||
requireFiles()
|
||||
.then( getForage )
|
||||
.then( async () => {
|
||||
|
||||
document.querySelector("#remotestorage-widget .rs-widget").classList.add(['blink'])
|
||||
if( opts.localstorage ){
|
||||
this.restore.localstorage.apply(this,opts) // default behaviour
|
||||
}
|
||||
if( opts.remotestorage ){
|
||||
localforage.setItem( "state", opts.data )
|
||||
.then( () => this.restore.localstorage.call(this,opts) ) // now trigger default behaviour
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
this.restore.localstorage = localRestore
|
||||
this.autorestore = this.restore // reroute automapping
|
||||
}
|
||||
|
||||
// decorate save() and restore() of autorestore.js after it's declared (hence the setTimeout)
|
||||
this.addEventListener('autorestore-installed', () => {
|
||||
decorateSave()
|
||||
decorateRestore()
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
// decorate autorestore
|
||||
const autorestoreLocalStorage = ISOTerminal.prototype.autorestore;
|
||||
ISOTerminal.prototype.autorestore = function(data){
|
||||
requireFiles().then( async () => {
|
||||
this.remoteStorageWidget()
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -40,6 +40,7 @@ this.runISO = async function(opts){
|
|||
emulator.add_listener("emulator-started", function(){
|
||||
importScripts("feat/9pfs_utils.js")
|
||||
this.postMessage({event:"emulator-started",data:false});
|
||||
if( opts.img ) this.restoreImage(opts)
|
||||
}.bind(this));
|
||||
|
||||
/*
|
||||
|
|
@ -66,13 +67,12 @@ this.runISO = async function(opts){
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
importScripts("feat/javascript.js")
|
||||
importScripts("feat/index.html.js")
|
||||
importScripts("feat/autorestore.js")
|
||||
|
||||
if( opts.overlayfs ) await this.addOverlayFS(opts)
|
||||
|
||||
}
|
||||
/*
|
||||
* forward events/functions so non-worker world can reach them
|
||||
|
|
@ -113,3 +113,21 @@ this.addOverlayFS = async function(opts){
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.restoreImage = function(opts){
|
||||
|
||||
this.postMessage({event:"serial0-output-string",data:`\n\r[!] loading session image:\n\r[!] ${opts.img}\n\r[!] please wait...internet speed matters here..\n`})
|
||||
|
||||
fetch( opts.img )
|
||||
.then( (res) => {
|
||||
this.postMessage({event:"serial0-output-string",data:`\r[v] image downloaded..restoring..\n\r`})
|
||||
return res
|
||||
})
|
||||
.then( (res) => res.arrayBuffer() )
|
||||
.then( async (buf) => {
|
||||
await this.emulator.restore_state(buf)
|
||||
this.postMessage({event:"serial0-output-string",data:`[v] restored\n\r`})
|
||||
|
||||
})
|
||||
.catch( console.error )
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ AFRAME.registerComponent('launcher', {
|
|||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
height: 50px;
|
||||
width:764px;
|
||||
overflow:hidden;
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
|
|
@ -307,6 +308,8 @@ AFRAME.registerSystem('launcher',{
|
|||
register: function(launchable){
|
||||
try{
|
||||
let {name, description, cb} = launchable
|
||||
const exist = this.registered.find( (r) => r.manifest.name == name )
|
||||
if( exist ) return // already registered
|
||||
this.registered.push({
|
||||
manifest: {name, description, icons: launchable.icon ? [{src:launchable.icon}] : [] },
|
||||
launcher: cb
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue