From 7a1fa9ba92c5478bc9ce877dc1b458bebf405421 Mon Sep 17 00:00:00 2001 From: tschudin Date: Fri, 2 Aug 2024 20:28:15 +0200 Subject: [PATCH] change ordering of posts to the causal ScuttleSort timeline way, not clock dependend anymore; fix 'wai not initialized' for good --- .../web/prod/dpi24-14-sched/scheduling_ui.js | 2 +- .../src/main/assets/web/prod/kanban/board.js | 1 + .../app/src/main/assets/web/prod/sketch.js | 21 ++-- .../app/src/main/assets/web/tremola.js | 96 ++++++++++++------- .../app/src/main/assets/web/tremola_ui.js | 14 ++- .../tremolavossbol/MainActivity.kt | 1 + .../nz/scuttlebutt/tremolavossbol/Settings.kt | 2 +- .../tremolavossbol/WebAppInterface.kt | 21 ++-- .../scuttlebutt/tremolavossbol/tssb/Node.kt | 2 +- .../scuttlebutt/tremolavossbol/tssb/Repo.kt | 2 +- 10 files changed, 100 insertions(+), 62 deletions(-) diff --git a/android/tinySSB/app/src/main/assets/web/prod/dpi24-14-sched/scheduling_ui.js b/android/tinySSB/app/src/main/assets/web/prod/dpi24-14-sched/scheduling_ui.js index cd043ae..99ec3f9 100644 --- a/android/tinySSB/app/src/main/assets/web/prod/dpi24-14-sched/scheduling_ui.js +++ b/android/tinySSB/app/src/main/assets/web/prod/dpi24-14-sched/scheduling_ui.js @@ -73,7 +73,7 @@ function dpi_load_event_list() { document.getElementById('lst:scheduling').innerHTML = ''; // console.log("tremola in load_ebent+list " + tremola) // if (tremola == undefined || !('event' in tremola) || Object.keys(tremola.event).length === 0) - if (Object.keys(tremola.event).length === 0) + if (!tremola.event || Object.keys(tremola.event).length === 0) return var subeventIds = Object.keys(tremola.event).filter(key => tremola.event[key].subscribed && !tremola.event[key].removed).map(key => ({[key]: tremola.event[key]})) if (subeventIds.length > 0) { diff --git a/android/tinySSB/app/src/main/assets/web/prod/kanban/board.js b/android/tinySSB/app/src/main/assets/web/prod/kanban/board.js index b3a157f..1a761bc 100644 --- a/android/tinySSB/app/src/main/assets/web/prod/kanban/board.js +++ b/android/tinySSB/app/src/main/assets/web/prod/kanban/board.js @@ -297,6 +297,7 @@ function kanban_new_event(e) { } if (board.subscribed) { + console.log(`board add ${prev}`) board.sortedOperations.add(e.header.ref, prev) var independentOPs = [Operation.COLUMN_CREATE, Operation.ITEM_CREATE, Operation.COLUMN_REMOVE, Operation.ITEM_REMOVE, Operation.LEAVE] // these operations cannot be overwritten; their position in the linear timeline does not affect the resulting board diff --git a/android/tinySSB/app/src/main/assets/web/prod/sketch.js b/android/tinySSB/app/src/main/assets/web/prod/sketch.js index 9099a96..488aef0 100644 --- a/android/tinySSB/app/src/main/assets/web/prod/sketch.js +++ b/android/tinySSB/app/src/main/assets/web/prod/sketch.js @@ -487,19 +487,26 @@ async function chat_sendDrawing() { } // send to backend - let recps; + var ch = tremola.chats[curr_chat] + if (!(ch.timeline instanceof Timeline)) { + ch.timeline = Timeline.fromJSON(ch.timeline) + } + let tips = JSON.stringify(ch.timeline.get_tips()) if (curr_chat == "ALL") { - recps = "ALL"; - backend("publ:post [] " + btoa(img) + " null"); // + recps) + var cmd = `publ:post ${tips} ` + btoa(img) + " null"; // + recps + // console.log(cmd) + backend(cmd); } else { - recps = tremola.chats[curr_chat].members.join(' '); - backend("priv:post [] " + btoa(img) + " null " + recps); + var recps = tremola.chats[curr_chat].members.join(' '); + var cmd = `priv:post ${tips} ` + btoa(img) + " null " + recps; + backend(cmd); } + closeOverlay(); - setTimeout(function () { // let image rendering (fetching size) take place before we scroll + // setTimeout(function () { // let image rendering (fetching size) take place before we scroll let c = document.getElementById('core'); c.scrollTop = c.scrollHeight; - }, 100); + // }, 100); // close sketch chat_closeSketch(); diff --git a/android/tinySSB/app/src/main/assets/web/tremola.js b/android/tinySSB/app/src/main/assets/web/tremola.js index 250559c..9657b8a 100644 --- a/android/tinySSB/app/src/main/assets/web/tremola.js +++ b/android/tinySSB/app/src/main/assets/web/tremola.js @@ -296,20 +296,27 @@ function new_text_post(s) { return; } var draft = unicodeStringToTypedArray(document.getElementById('draft').value); // escapeHTML( - var recps; + var ch = tremola.chats[curr_chat] + if (!(ch.timeline instanceof Timeline)) { + ch.timeline = Timeline.fromJSON(ch.timeline) + } + let tips = JSON.stringify(ch.timeline.get_tips()) + // console.log(`tips: ${tips}`) if (curr_chat == "ALL") { - recps = "ALL"; - backend("publ:post [] " + btoa(draft) + " null"); // + recps) + var cmd = `publ:post ${tips} ` + btoa(draft) + " null"; // + recps + // console.log(cmd) + backend(cmd); } else { - recps = tremola.chats[curr_chat].members.join(' '); - backend("priv:post [] " + btoa(draft) + " null " + recps); + var recps = tremola.chats[curr_chat].members.join(' '); + var cmd = `priv:post ${tips} ` + btoa(draft) + " null " + recps; + backend(cmd); } document.getElementById('draft').value = ''; closeOverlay(); setTimeout(function () { // let image rendering (fetching size) take place before we scroll var c = document.getElementById('core'); c.scrollTop = c.scrollHeight; - }, 100); + }, 100); } function new_voice_post(voice_b64) { @@ -318,12 +325,21 @@ function new_voice_post(voice_b64) { draft = "null" else draft = btoa(draft) + var ch = tremola.chats[curr_chat] + if (!(ch.timeline instanceof Timeline)) { + ch.timeline = Timeline.fromJSON(ch.timeline) + } + let tips = JSON.stringify(ch.timeline.get_tips()) + // console.log(`tips: ${tips}`) + if (curr_chat == "ALL") { - // recps = "ALL"; - backend("publ:post [] " + draft + " " + voice_b64); // + recps) + var cmd = `publ:post ${tips} ` + draft + " " + voice_b64; + // console.log(cmd) + backend(cmd); } else { - recps = tremola.chats[curr_chat].members.join(' '); - backend("priv:post [] " + draft + " " + voice_b64 + " " + recps); + var recps = tremola.chats[curr_chat].members.join(' '); + var cmd = `priv:post ${tips} ` + draft + " " + voice_b64 + " " + recps; + backend(cmd); } document.getElementById('draft').value = ''; } @@ -469,6 +485,10 @@ function load_chat(nm) { } pl.insertRow(0).innerHTML = "     "; curr_chat = nm; + for (var n of ch.timeline.linear) { + load_post_item(ch.posts[n.name]) + } + /* var lop = []; // list of posts for (var p in ch.posts) lop.push(p) lop.sort(function (a, b) { @@ -477,6 +497,7 @@ function load_chat(nm) { lop.forEach(function (p) { load_post_item(ch.posts[p]) }) + */ load_chat_title(ch); setScenario("posts"); document.getElementById("tremolaTitle").style.display = 'none'; @@ -484,10 +505,6 @@ function load_chat(nm) { ch["lastRead"] = Date.now(); persist(); document.getElementById(nm + '-badge').style.display = 'none' // is this necessary? - setTimeout(function () { // let image rendering (fetching size) take place before we scroll - var c = document.getElementById('core'); - c.scrollTop = c.scrollHeight; - }, 100); /* // scroll to bottom: var c = document.getElementById('core'); @@ -627,7 +644,7 @@ function show_contact_details(id) { } var c = tremola.contacts[id]; new_contact_id = id; - document.getElementById('old_contact_alias').value = c['alias']; + document.getElementById('old_contact_alias').value = c.alias ? c['alias'] : ""; var details = ''; details += '
IAM-Alias:  ' + (c.iam != "" ? c.iam : "—") + '
\n'; details += '
Shortname:  ' + id2b32(id) + '
\n'; @@ -780,7 +797,8 @@ function new_conversation() { if (!(nm in tremola.chats)) { tremola.chats[nm] = { "alias": "Private", "posts": {}, - "members": recps, "touched": Date.now(), "timeline": new Timeline() + "members": recps, "touched": Date.now(), + "timeline": new Timeline() }; persist(); } else @@ -899,6 +917,7 @@ function escapeHTML(str) { function recps2nm(rcps) { // use concat of sorted FIDs as internal name for conversation // return "ALL"; + // console.log(`recps2nm ${rcps}`) return rcps.sort().join('').replace(/.ed25519/g, ''); } @@ -1137,7 +1156,7 @@ function b2f_new_in_order_event(e) { load_contact_list() } - switch (e.public[0]) { + if (e.public) switch (e.public[0]) { case "KAN": console.log("New kanban event") kanban_new_event(e) @@ -1230,20 +1249,23 @@ function b2f_new_event(e) { // incoming SSB log event: we get map with three ent }; load_chat_list() } - console.log("new post 1") + // console.log("new post 1") var ch = tremola.chats[conv_name]; - if (ch.timeline == null) - ch["timeline"] = new Timeline(); - console.log("new post 1 ", ch) + if (!(ch.timeline instanceof Timeline)) { + ch.timeline = Timeline.fromJSON(ch.timeline) + } + // console.log("new post 1 ", ch) if (!(e.header.ref in ch.posts)) { // new post var a = e.public; var p = { - "key": e.header.ref, "from": e.header.fid, "body": a[1], - "voice": a[2], "when": a[3] * 1000 + "key": e.header.ref, "from": e.header.fid, "body": a[2], + "voice": a[3], "when": a[4] * 1000, "prev": a[1] }; - console.log("new post 2 ", p) - console.log("time: ", a[3]) + // console.log("new post 2 ", JSON.stringify(p)) + // console.log("time: ", a[3]) ch["posts"][e.header.ref] = p; + // console.log(`chat add ${a[1]}`) + ch.timeline.add(e.header.ref, a[1]) if (ch["touched"] < e.header.tst) ch["touched"] = e.header.tst if (curr_scenario == "posts" && curr_chat == conv_name) { @@ -1252,7 +1274,7 @@ function b2f_new_event(e) { // incoming SSB log event: we get map with three ent } set_chats_badge(conv_name) } else { - console.log("known already?") + console.log(`post ${e.header.ref} known already?`) } // if (curr_scenario == "chats") // the updated conversation could bubble up load_chat_list(); @@ -1287,30 +1309,34 @@ function b2f_new_event(e) { // incoming SSB log event: we get map with three ent if (e.confid) { if (e.confid[0] == 'TAV') { // text and voice console.log("new priv post 0 ", tremola) - var conv_name = recps2nm(e.confid[4]); + var conv_name = recps2nm(e.confid[5]); if (!(conv_name in tremola.chats)) { // create new conversation if needed console.log("xx") tremola.chats[conv_name] = { - "alias": recps2display(e.confid[4]), "posts": {}, - "members": e.confid[4], "touched": Date.now(), "lastRead": 0, + "alias": recps2display(e.confid[5]), "posts": {}, + "members": e.confid[5], "touched": Date.now(), "lastRead": 0, "timeline": new Timeline() }; load_chat_list() } - console.log("new priv post 1") + // console.log("new priv post 1") var ch = tremola.chats[conv_name]; if (ch.timeline == null) ch["timeline"] = new Timeline(); - console.log("new priv post 1 ", ch) + else if (!(ch.timeline instanceof Timeline)) + ch.timeline = Timeline.fromJSON(ch.timeline) + // console.log("new priv post 1 ", ch) if (!(e.header.ref in ch.posts)) { // new post var a = e.confid; var p = { - "key": e.header.ref, "from": e.header.fid, "body": a[1], - "voice": a[2], "when": a[3] * 1000 + "key": e.header.ref, "from": e.header.fid, "body": a[2], + "voice": a[3], "when": a[4] * 1000, "prev": a[1] }; - console.log("new priv post 2 ", p) - console.log("time: ", a[3]) + // console.log("new priv post 2 ", p) + // console.log("time: ", a[3]) ch["posts"][e.header.ref] = p; + // console.log(`chat add ${a[1]}`) + ch.timeline.add(e.header.ref, a[1]) if (ch["touched"] < e.header.tst) ch["touched"] = e.header.tst if (curr_scenario == "posts" && curr_chat == conv_name) { diff --git a/android/tinySSB/app/src/main/assets/web/tremola_ui.js b/android/tinySSB/app/src/main/assets/web/tremola_ui.js index 22c26f3..a6f9646 100644 --- a/android/tinySSB/app/src/main/assets/web/tremola_ui.js +++ b/android/tinySSB/app/src/main/assets/web/tremola_ui.js @@ -199,14 +199,12 @@ function setScenario(s) { } if (s == 'posts') { - // FIXME: the following does not reliably scroll to the end ... - let p = document.getElementById('div:posts'); - // console.log("scroll 1 " + p.scrollHeight) - p.scrollTop = p.scrollHeight; - // p.scrollTo(0, p.scrollHeight); // has same problem - - // var pl = document.getElementById('lst:posts'); // has same problem - // pl.rows[pl.rows.length-1].scrollIntoView() + setTimeout(function () { // let image rendering (fetching size) take place before we scroll + let c = document.getElementById('core'); + c.scrollTop = c.scrollHeight; + let p = document.getElementById('div:posts'); + p.scrollTop = p.scrollHeight; + }, 100); } if (s == 'scheduling') { diff --git a/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/MainActivity.kt b/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/MainActivity.kt index 564ccae..8c2d89f 100644 --- a/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/MainActivity.kt +++ b/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/MainActivity.kt @@ -41,6 +41,7 @@ class MainActivity : Activity() { lateinit var idStore: IdStore lateinit var wai: WebAppInterface lateinit var tinyIO: IO + var frontend_ready = false val tinyNode = Node(this) val tinyRepo = Repo(this) val tinyDemux = Demux(this) diff --git a/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/Settings.kt b/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/Settings.kt index 4042e67..e7d0cfc 100644 --- a/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/Settings.kt +++ b/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/Settings.kt @@ -19,7 +19,7 @@ class Settings(val context: MainActivity) { // backend settings "ble_enabled" to "true", "udp_multicast_enabled" to "true", - "websocket_enabled" to "true", + "websocket_enabled" to "false", "websocket_url" to TINYSSB_SIMPLEPUB_URL ) fun getSettings(): String { diff --git a/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/WebAppInterface.kt b/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/WebAppInterface.kt index 0702de6..b066535 100644 --- a/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/WebAppInterface.kt +++ b/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/WebAppInterface.kt @@ -33,7 +33,6 @@ import org.json.JSONArray class WebAppInterface(val act: MainActivity, val webView: WebView) { - var frontend_ready = false val frontend_frontier = act.getSharedPreferences("frontend_frontier", Context.MODE_PRIVATE) @JavascriptInterface @@ -47,7 +46,7 @@ class WebAppInterface(val act: MainActivity, val webView: WebView) { } "ready" -> { eval("b2f_initialize('${act.idStore.identity.toRef()}', '${act.settings!!.getSettings()}')") - frontend_ready = true + act.frontend_ready = true act.tinyRepo.addNumberOfPendingChunks(0) // initialize chunk progress bar act.tinyNode.beacon() } @@ -154,8 +153,7 @@ class WebAppInterface(val act: MainActivity, val webView: WebView) { val a = JSONArray(args[1]) val tips = ArrayList(0) for (i in 0..a.length()-1) { - val s = (a[i] as JSONObject).toString() - Log.d("publ:post", s) + val s = a[i].toString() // (a[i] as JSONObject).toString() tips.add(s) } var t: String? = null @@ -171,8 +169,7 @@ class WebAppInterface(val act: MainActivity, val webView: WebView) { val a = JSONArray(args[1]) val tips = ArrayList(0) for (i in 0..a.length()-1) { - val s = (a[i] as JSONObject).toString() - Log.d("priv:post", s) + val s = a[i].toString() // (a[i] as JSONObject).toString() tips.add(s) } var t: String? = null @@ -288,7 +285,11 @@ class WebAppInterface(val act: MainActivity, val webView: WebView) { Log.d("wai", "post_voice v- ${voice}/${voice.size}") val lst = Bipf.mkList() Bipf.list_append(lst, TINYSSB_APP_TEXTANDVOICE) - // add tips + val tip_lst = Bipf.mkList() + for (t in tips) { + Bipf.list_append(tip_lst, Bipf.mkString(t)) + } + Bipf.list_append(lst, tip_lst) Bipf.list_append(lst, if (text == null) Bipf.mkNone() else Bipf.mkString(text)) Bipf.list_append(lst, if (voice == null) Bipf.mkNone() else Bipf.mkBytes(voice)) val tst = Bipf.mkInt((System.currentTimeMillis() / 1000).toInt()) @@ -306,7 +307,11 @@ class WebAppInterface(val act: MainActivity, val webView: WebView) { Log.d("wai", "private post_voice v- ${voice}/${voice.size}") val lst = Bipf.mkList() Bipf.list_append(lst, TINYSSB_APP_TEXTANDVOICE) - // add tips + val tip_lst = Bipf.mkList() + for (t in tips) { + Bipf.list_append(tip_lst, Bipf.mkString(t)) + } + Bipf.list_append(lst, tip_lst) Bipf.list_append(lst, if (text == null) Bipf.mkNone() else Bipf.mkString(text)) Bipf.list_append(lst, if (voice == null) Bipf.mkNone() else Bipf.mkBytes(voice)) val tst = Bipf.mkInt((System.currentTimeMillis() / 1000).toInt()) diff --git a/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/tssb/Node.kt b/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/tssb/Node.kt index 0ad4498..259c292 100644 --- a/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/tssb/Node.kt +++ b/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/tssb/Node.kt @@ -193,7 +193,7 @@ class Node(val context: MainActivity) { // calculates current replication progress and sends update to frontend fun update_progress(want_vector: List, from: String) { - if (!context.wai.frontend_ready) + if (!context.frontend_ready) return var wantsChanged = false // if want vectors did change diff --git a/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/tssb/Repo.kt b/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/tssb/Repo.kt index 062f8e4..829ebb1 100644 --- a/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/tssb/Repo.kt +++ b/android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/tssb/Repo.kt @@ -85,7 +85,7 @@ class Repo(val context: MainActivity) { chnk_offs = Random.nextInt(0, context.tinyGoset.keys.size - 1) } - if(context.wai.frontend_ready) // was: isWaiInitialized() + if(context.frontend_ready) // was: isWaiInitialized() context.wai.eval("b2f_new_contact(\"@${fid.toBase64()}.ed25519\")") // notify frontend // want_is_valid = false