From 4a6a4ff699ee789cc24cde479be332ce3721d98e Mon Sep 17 00:00:00 2001 From: Jake <jake.read@cba.mit.edu> Date: Thu, 9 May 2019 22:29:46 -0400 Subject: [PATCH] patches and bootstraps --- README.md | 7 ++- hunks/comm/websocketclient.js | 10 +++- hunks/view.js | 6 +++ programs/{ => cuttlefish}/wstst.json | 12 ++++- programs/nautilus/ntsave.json | 22 ++++++++ programs/tptch.json | 42 --------------- style.css | 21 ++++++++ view/vdef.js | 8 +-- view/vmsg.js | 13 ++++- view/vptch.js | 81 +++++++++++++++++++++++----- 10 files changed, 159 insertions(+), 63 deletions(-) rename programs/{ => cuttlefish}/wstst.json (88%) create mode 100644 programs/nautilus/ntsave.json delete mode 100644 programs/tptch.json diff --git a/README.md b/README.md index 4d12802..f84ccd5 100644 --- a/README.md +++ b/README.md @@ -18,11 +18,16 @@ Native Cuttlefish 'Hunks' are given access to a DOM/div element, making them nic IAA ... it's all addressing -> -> -remote managers can't just throw messages about: they have to have some contextual awareness of the view ? or their connectedness ? can keep existing structure and just wait until have-said-hello or not +remote managers can't just throw messages about: they have to have some contextual awareness of the view ? or their connectedness ? can keep existing structure and just wait until have-said-hello or not + + -> added 'isConnectedTo' feature, won't work when connections disappear though ! + +... so, and view needs to be sensitive to that, and watch state on a refresh also ? ... towards decent views ... and a debug-thru-cuttlefish portal for ponyo - patchload is nice, ok, this direction - layout ... save positions in patches ? unf- force layout ? + - write cobs, and a cobs patch -> proto logs out into a browser - ... link work ? ... links agreeing with one another before startup - results in link saying 'updatehunkdefinition' and manager ... reporting ? or not ? - load -> then load -> then log, up through a few links diff --git a/hunks/comm/websocketclient.js b/hunks/comm/websocketclient.js index dc22b8c..94b5797 100644 --- a/hunks/comm/websocketclient.js +++ b/hunks/comm/websocketclient.js @@ -26,9 +26,10 @@ function WebSocketClient() { // this is hunk -> manager commune ... let statusMessage = new State('string', 'status', 'closed') let retryCountHandle = new State('number', 'retrycount', 3) + let resetRetryHandle = new State('boolean', 'retryreset', false) let addressState = new State('string', 'address', '127.0.0.1') let portState = new State('number', 'port', 2042) - this.states.push(statusMessage, retryCountHandle, addressState, portState) + this.states.push(statusMessage, retryCountHandle, resetRetryHandle, addressState, portState) // this ws is a client, let ws = {} @@ -39,6 +40,13 @@ function WebSocketClient() { setTimeout(startWs, 500) } + resetRetryHandle.change = (value) => { + retryCountHandle.set(3) + startWs() + // to actually change the value, we would do: + // resetRetryHandle.set(value) + } + let startWs = () => { // manager calls this once // it is loaded and state is updated (from program) diff --git a/hunks/view.js b/hunks/view.js index 74266ae..4e914ef 100644 --- a/hunks/view.js +++ b/hunks/view.js @@ -55,12 +55,16 @@ function View() { // we have a list of definitions, let defs = new Array() + // #ref, sloppy + this.defs = defs // tools to write dom-representations of hunks, let dt = new DomTools(this) // a handy box, for stuff let msgbox = new MessageBox(this) this.msgbox = msgbox + this.interpreterName = null + this.interpreterVersion = null // and tools for the links, let bzt = new BezierTools(this) // and for program (patch) management @@ -880,6 +884,7 @@ function View() { msgbox.briefState.decrementHunks() msgbox.write(`added a new hunk: ${spec.name}`) patchset.onHunkLoaded(nd) + $(this.dom).find('.contextmenu').remove() } else { if(verbose) console.log('replacing hunk at', spec.ind) replaceDef(spec) @@ -899,6 +904,7 @@ function View() { stDef = defs[stchHnkInd].states[stchStInd] let stValUpdate = MSGS.readFrom(msg, 6, stDef.type).item stDef.set(stValUpdate) + patchset.onStateChanged(stDef) msgbox.write(`changed state at ${stchHnkInd} ${stDef.name} to ${stValUpdate}`) } catch (err) { console.error('likely error from state change indexing', err) diff --git a/programs/wstst.json b/programs/cuttlefish/wstst.json similarity index 88% rename from programs/wstst.json rename to programs/cuttlefish/wstst.json index 20e9a83..f87cc4f 100644 --- a/programs/wstst.json +++ b/programs/cuttlefish/wstst.json @@ -2,6 +2,12 @@ "interpreterName": "cuttlefish", "interpreterVersion": "v0.1", "hunks": [{ + "name": "manager", + "states": [] + }, { + "name": "view", + "states": [] + }, { "name": "link", "states": [{ "ind": 0, @@ -34,10 +40,14 @@ "value": 3 }, { "ind": 2, + "type": "boolean", + "value": false + }, { + "ind": 3, "type": "string", "value": "127.0.0.1" }, { - "ind": 3, + "ind": 4, "type": "number", "value": 2042 }] diff --git a/programs/nautilus/ntsave.json b/programs/nautilus/ntsave.json new file mode 100644 index 0000000..3522a98 --- /dev/null +++ b/programs/nautilus/ntsave.json @@ -0,0 +1,22 @@ +{ + "interpreterName": "cuttlefish", + "interpreterVersion": "v0.1", + "hunks": [{ + "name": "comm/websocketserver", + "states": [{ + "ind": 0, + "type": "string", + "value": "connected" + }, { + "ind": 1, + "type": "number", + "value": 2042 + }] + }], + "links": [{ + "outInd": 2, + "outputInd": 0, + "inInd": 1, + "inputInd": 0 + }] +} diff --git a/programs/tptch.json b/programs/tptch.json deleted file mode 100644 index 6db7ced..0000000 --- a/programs/tptch.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "interpreterName": "cuttlefish", - "interpreterVersion": "v0.1", - "hunks": [{ - "name": "link", - "states": [{ - "ind": 0, - "type": "string", - "value": "mgrMsgs (byteArray), numtype (number)" - }, { - "ind": 1, - "type": "string", - "value": "mgrMsgs (byteArray), numoot (number)" - }] - }, { - "name": "view", - "states": [] - }, { - "name": "interface/number", - "states": [{ - "ind": 0, - "type": "number", - "value": 12 - }] - }], - "links": [{ - "outInd": 2, - "outputInd": 1, - "inInd": 3, - "inputInd": 0 - }, { - "outInd": 3, - "outputInd": 0, - "inInd": 2, - "inputInd": 1 - }, { - "outInd": 4, - "outputInd": 0, - "inInd": 2, - "inputInd": 2 - }] -} diff --git a/style.css b/style.css index 76a5125..efe1d8a 100644 --- a/style.css +++ b/style.css @@ -215,17 +215,38 @@ textarea { } */ +.stateItem { + margin: 3px; +} + .stateItem input { background-color: #1a1a1a; color: #fcd17b; font-size: 12px; width: 70%; margin-bottom: 2px; + margin-top: 4px; padding: 2px; border: 1px solid black; border-radius: 3px; } +.stateNumInput input { + float: right; + clear: both; + align: right; +} + +.stateBooleanItem{ + padding-top: 8px; + padding-bottom: 8px; +} + +.stateBooleanItem:hover{ + background-color: #1a1a1a; + cursor: pointer; +} + .dg.a { margin-right: 0px; } diff --git a/view/vdef.js b/view/vdef.js index a9b8055..edc368a 100644 --- a/view/vdef.js +++ b/view/vdef.js @@ -261,7 +261,7 @@ function StateDefinition(stspec, ind, def, view, debug){ // business, this.value = stspec.value // ok, - this.de = $('<div><p>' + this.name + " (" + this.type + ")" + '</p></div>').addClass('stateItem').get(0) + this.de = $('<div>' + this.name + " (" + this.type + ")" + '</div>').addClass('stateItem').get(0) this.de.id = `${this.parent.name}_${this.parent.ind}_state_${this.name}` this.newParentInd = () => { this.de.id = `${this.parent.name}_${this.parent.ind}_state_${this.name}` @@ -292,7 +292,7 @@ function StateDefinition(stspec, ind, def, view, debug){ } break // end string types case 'number': - let ninput = $('<input>').attr('type', 'text').attr('size', 24).attr('value', this.value.toString()).css('width', '100px').get(0) + let ninput = $('<input>').addClass('stateNumInput').attr('type', 'text').attr('size', 24).attr('value', this.value.toString()).css('width', '100px').get(0) ninput.addEventListener('change', (evt) => { // ask for a change, view.requestStateChange(this, parseFloat(ninput.value)) @@ -312,6 +312,8 @@ function StateDefinition(stspec, ind, def, view, debug){ break // end numnber type case 'boolean': let span = $('<span style="float:right;">' + this.value.toString() + '</span>').get(0) + $(this.de).addClass('stateBooleanItem') + this.de.append(span) this.de.addEventListener('click', (evt) => { // read the current 'state' (as written) and send the opposite let txt = $(span).text() @@ -324,7 +326,7 @@ function StateDefinition(stspec, ind, def, view, debug){ this.set = (value) => { if(typeof value === boolean){ $(span).text(value.toString()) - this.value = value + this.value = value } else { throw new Error('bad type put into state dom') } diff --git a/view/vmsg.js b/view/vmsg.js index a45b635..da952e5 100644 --- a/view/vmsg.js +++ b/view/vmsg.js @@ -11,6 +11,7 @@ function MessageBox(View) { recipVersion: '', numHunksLeft: 0, numLinksLeft: 0, + isStateHappenning: false, setFromBrief: function(brief) { this.recipVer = brief.interpreterVersion this.recipName = brief.interpreterName @@ -18,6 +19,14 @@ function MessageBox(View) { this.numLinksLeft = brief.numLinks this.postToDom() }, + stateIsHappening: function() { + this.isStateHappenning = true + this.postToDom() + }, + stateIsNotHappening: function() { + this.isStateHappenning = false + this.postToDom() + }, decrementHunks: function() { this.numHunksLeft-- this.postToDom() @@ -36,7 +45,9 @@ function MessageBox(View) { }, postToDom: function() { let str - if (this.numHunksLeft > 0 || this.numLinksLeft > 0) { + if(this.stateIsHappening){ + str = `manager interpreter: ${this.recipName} ${this.recipVer} <br> awaiting state ...` + } else if (this.numHunksLeft > 0 || this.numLinksLeft > 0) { str = `manager interpreter: ${this.recipName} ${this.recipVer} <br> awaiting ${this.numHunksLeft} hunks and ${this.numLinksLeft} links` } else { str = `manager interpreter: ${this.recipName} ${this.recipVer} <br> all loaded OK` diff --git a/view/vptch.js b/view/vptch.js index fa45a19..e0b51af 100644 --- a/view/vptch.js +++ b/view/vptch.js @@ -14,8 +14,12 @@ function PatchSet(View, MsgBox) { // load from server should be assumed, just rip that *baybie* this.findPatches = (evt) => { // and then, + if (!(view.interpreterName)) { + msgbox.write('view on unknown interpeter, cannot save ... refresh view first') + return false + } $(evt.target).append(' > loading a list ...') - gg.recursivePathSearch('programs', '.json', true).then((list) => { + gg.recursivePathSearch('programs/' + view.interpreterName + '/', '.json', true).then((list) => { console.log('returns list', list) // title, and options view.changeContextTitle('available patches:') @@ -33,26 +37,75 @@ function PatchSet(View, MsgBox) { }) } + let patchStep = 0 let unloadedHunks = [] + let awaitStates = [] let unloadedLinks = [] let reqNextHunk = () => { - // from 0th position in array - msgbox.briefState.incrementHunks() - console.log('loading hunk from', unloadedHunks[0]) - view.requestAddHunk(unloadedHunks[0].name, unloadedHunks[0].states) + // patchStep is the expected current place in an array of hunks, if + if (view.defs[patchStep] !== undefined) { // have one of these already, + if (view.defs[patchStep].name === unloadedHunks[0].name) { + msgbox.write(`found write-over for ${unloadedHunks[0].name}, checking for req change`) + // look at each state, + if (view.defs[patchStep].states.length < 1) { + unloadedHunks.shift() + patchStep ++ + reqNextHunk() // recursive? pretty sure this is fn completion + } else { + for (let st in view.defs[patchStep].states) { + // might be a few of these, and there might be none + if (view.defs[patchStep].states[st].value !== unloadedHunks[0].states[st].value) { + view.requestStateChange(view.defs[patchStep].states[st], unloadedHunks[0].states[st].value) + // we have to track this ... + msgbox.briefState.stateIsHappening() + awaitState.push(view.defs[patchStep].states[st].name) + } + } + } + } else { + // an error, the in-place hunk doesn't exist here + // this is a hack for now ... we are assuming all contexts are starting from bootstrap, + // and that exactly that bootstrap is running already + msgbox.write('lost bootstrap, or existing program, while loading a patch') + console.error(`lost bootstrap, or existing program, while loading a patch: ${patchStep}, ulh, ${unloadedHunks[0].name}, defs, ${view.defs[patchStep].name}`); + } + } else { + // regular ops, + msgbox.briefState.incrementHunks() + console.log('loading hunk from', unloadedHunks[0]) + view.requestAddHunk(unloadedHunks[0].name, unloadedHunks[0].states) + } + } + + this.onStateChanged = (stateDef) => { + if(awaitStates.length < 1) return true + let indOf = awaitStates.indexOf(stateDef.name) + if(indOf === -1){ + console.error(`misplaced state: ${stateDef.name}`) + } else { + awaitStates.splice(indOf, 1) + if(awaitStates.length < 0){ + msgbox.briefState.stateIsNotHappening() + unloadedHunks.shift() + reqNextHunk() + } + } } // callbacks, this.onHunkLoaded = (def) => { // not interested, if (unloadedHunks.length < 1) return true + // ur loaded, + patchStep++ // ok ... // find in list, rm console.log('checking', def, 'against', unloadedHunks[0]) // check that we *are* receiving in order let checksOut = true if (def.name !== unloadedHunks[0].name) checksOut = false + // on a state update case, we might have different states ... for now, avoiding this problem for (let st in def.states) { if (def.states[st].value !== unloadedHunks[0].states[st].value) checksOut = false } @@ -99,7 +152,7 @@ function PatchSet(View, MsgBox) { this.loadPatch = (name) => { msgbox.write(`ok, loading a patch from: ${name}`) - gg.getJson('/programs/' + name + '.json').then((patch) => { + gg.getJson('/programs/' + view.interpreterName + '/' + name + '.json').then((patch) => { console.log('the patch', patch) if (patch.interpreterName !== view.interpreterName) { msgbox.write(`WARN: loading patch built in a different interpreter... some hunks may not exist: patch for: "${patch.interpreterName}", but view is connected to "${view.interpreterName}"`) @@ -121,19 +174,19 @@ function PatchSet(View, MsgBox) { this.saveCurrent = (evt, defs, debug) => { if (debug) console.log('saving ...') - // riperoni ok + // riperoni ok, save them all let patch = { - interpreterName: gg.interpreterName, - interpreterVersion: gg.interpreterVersion, + // cerntakt + interpreterName: view.interpreterName, + interpreterVersion: view.interpreterVersion, hunks: [], links: [] // links added later } // the hunks, for (let df of defs) { - // exclude bootstrap hunks, for us for now this is just the first two - if (df.ind === 0 || df.ind === 1) continue - // otherwise + // we save them all, + // on load, compare to existing in same position console.log('writing prep for', df) // in order, u c let prep = { @@ -141,7 +194,7 @@ function PatchSet(View, MsgBox) { states: [] } // HERE: we save state just with the index / value ? - if(df.states !== undefined){ + if (df.states !== undefined) { for (let st of df.states) { prep.states.push({ ind: st.ind, @@ -152,7 +205,7 @@ function PatchSet(View, MsgBox) { } // roll for links, // outputs - if(df.outputs !== undefined){ + if (df.outputs !== undefined) { for (let otp in df.outputs) { for (let cn in df.outputs[otp].connections) { patch.links.push({ -- GitLab