Skip to content

Commit 59c6698

Browse files
authored
Merge pull request #10 from ssbc/apk_in-order-delivery
android: add additional frontend callbacks for received log entries
2 parents d3d7978 + acd110b commit 59c6698

4 files changed

Lines changed: 127 additions & 13 deletions

File tree

android/tinySSB/app/src/main/assets/web/tremola.js

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,89 @@ function b2f_local_peer(type, identifier, displayname, status) {
10191019
refresh_connection_entry(identifier)
10201020
}
10211021

1022+
/**
1023+
* This function is called, when the backend received a new log entry and successfully completed the corresponding sidechain.
1024+
* The backend assures, that the log entries are sent to the frontend in the exact same sequential order as in the append-only log.
1025+
*
1026+
* @param {Object} e Object containing all information of the log_entry.
1027+
* @param {Object} e.hdr Contains basic information about the log entry.
1028+
* @param {number} e.hdr.tst Timestamp at which the message was created. (Number of milliseconds elapsed since midnight at the beginning of January 1970 00:00 UTC)
1029+
* @param {string} e.hdr.ref The message ID of this log entry.
1030+
* @param {string} e.hdr.fid The public key of the author encoded in base64.
1031+
* @param {[]} e.public The payload of the message. The first entry is a String that represents the application to which the message belongs. All additional entries are application-specific parameters.
1032+
*
1033+
*/
1034+
function b2f_new_in_order_event(e) {
1035+
1036+
console.log("b2f inorder event:", JSON.stringify(e.public))
1037+
1038+
if (!(e.header.fid in tremola.contacts)) {
1039+
var a = id2b32(e.header.fid);
1040+
tremola.contacts[e.header.fid] = {
1041+
"alias": a, "initial": a.substring(0, 1).toUpperCase(),
1042+
"color": colors[Math.floor(colors.length * Math.random())],
1043+
"iam": "", "forgotten": false
1044+
}
1045+
load_contact_list()
1046+
}
1047+
1048+
switch (e.public[0]) {
1049+
case "KAN":
1050+
console.log("New kanban event")
1051+
kanban_new_event(e)
1052+
break
1053+
default:
1054+
return
1055+
}
1056+
persist();
1057+
must_redraw = true;
1058+
}
1059+
1060+
/**
1061+
* This function is invoked whenever the backend receives a new log entry, regardless of whether the associated sidechain is fully loaded or not.
1062+
*
1063+
* @param {Object} e Object containing all information of the log_entry.
1064+
* @param {Object} e.hdr Contains basic information about the log entry.
1065+
* @param {number} e.hdr.tst Timestamp at which the message was created. (Number of milliseconds elapsed since midnight at the beginning of January 1970 00:00 UTC)
1066+
* @param {string} e.hdr.ref The message ID of this log entry.
1067+
* @param {string} e.hdr.fid The public key of the author encoded in base64.
1068+
* @param {[]} e.public The payload of the logentry, without the content of the sidechain
1069+
*
1070+
*/
1071+
function b2f_new_incomplete_event(e) {
1072+
1073+
if (!(e.header.fid in tremola.contacts)) {
1074+
var a = id2b32(e.header.fid);
1075+
tremola.contacts[e.header.fid] = {
1076+
"alias": a, "initial": a.substring(0, 1).toUpperCase(),
1077+
"color": colors[Math.floor(colors.length * Math.random())],
1078+
"iam": "", "forgotten": false
1079+
}
1080+
load_contact_list()
1081+
}
1082+
1083+
switch (e.public[0]) {
1084+
default:
1085+
return
1086+
}
1087+
persist();
1088+
must_redraw = true;
1089+
1090+
1091+
}
1092+
1093+
/**
1094+
* This function is called, when the backend received a new log entry and successfully completed the corresponding sidechain.
1095+
* This callback does not ensure any specific order; the log entries are forwarded in the order they are received.
1096+
*
1097+
* @param {Object} e Object containing all information of the log_entry.
1098+
* @param {Object} e.hdr Contains basic information about the log entry.
1099+
* @param {number} e.hdr.tst Timestamp at which the message was created. (Number of milliseconds elapsed since midnight at the beginning of January 1970 00:00 UTC)
1100+
* @param {string} e.hdr.ref The message ID of this log entry.
1101+
* @param {string} e.hdr.fid The public key of the author encoded in base64.
1102+
* @param {[]} e.public The payload of the message. The first entry is a String that represents the application to which the message belongs. All additional entries are application-specific parameters.
1103+
*
1104+
*/
10221105
function b2f_new_event(e) { // incoming SSB log event: we get map with three entries
10231106
// console.log('hdr', JSON.stringify(e.header))
10241107
console.log('pub', JSON.stringify(e.public))
@@ -1081,8 +1164,6 @@ function b2f_new_event(e) { // incoming SSB log event: we get map with three ent
10811164
// if (curr_scenario == "chats") // the updated conversation could bubble up
10821165
load_chat_list();
10831166
} else if (e.public[0] == "KAN") { // Kanban board event
1084-
console.log("New kanban event")
1085-
kanban_new_event(e)
10861167
} else if (e.public[0] == "IAM") {
10871168
var contact = tremola.contacts[e.header.fid]
10881169
var old_iam = contact.iam

android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/WebAppInterface.kt

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package nz.scuttlebutt.tremolavossbol
33
import android.Manifest
44
import android.content.ClipData
55
import android.content.ClipboardManager
6+
import android.content.Context
67
import android.content.Intent
78
import android.content.pm.PackageManager
89
import android.util.Base64
@@ -30,6 +31,7 @@ import org.json.JSONArray
3031
class WebAppInterface(val act: MainActivity, val webView: WebView) {
3132

3233
var frontend_ready = false
34+
val frontend_frontier = act.getSharedPreferences("frontend_frontier", Context.MODE_PRIVATE)
3335

3436
@JavascriptInterface
3537
fun onFrontendRequest(s: String) {
@@ -63,7 +65,7 @@ class WebAppInterface(val act: MainActivity, val webView: WebView) {
6365
val mid = r.get_mid(i)
6466
if (payload == null || mid == null) break
6567
Log.d("restream", "${i}, ${payload.size} Bytes")
66-
sendToFrontend(fid, i, mid, payload)
68+
sendTinyEventToFrontend(fid, i, mid, payload)
6769
i++
6870
}
6971
}
@@ -353,28 +355,48 @@ class WebAppInterface(val act: MainActivity, val webView: WebView) {
353355
eval(cmd)
354356
}
355357

358+
fun sendIncompleteEntryToFrontend(fid: ByteArray, seq: Int, mid:ByteArray, body: ByteArray) {
359+
val e = toFrontendObject(fid, seq, mid, body)
360+
if (e != null)
361+
eval("b2f_new_incomplete_event($e)")
362+
363+
}
364+
356365
fun sendTinyEventToFrontend(fid: ByteArray, seq: Int, mid:ByteArray, body: ByteArray) {
357366
Log.d("wai","sendTinyEvent ${body.toHex()}")
358-
sendToFrontend(fid, seq, mid, body)
367+
var e = toFrontendObject(fid, seq, mid, body)
368+
if (e != null)
369+
eval("b2f_new_event($e)")
370+
371+
// in-order api
372+
val replica = act.tinyRepo.fid2replica(fid)
373+
374+
if (frontend_frontier.getInt(fid.toHex(), 1) == seq && replica != null) {
375+
for (i in seq .. replica.state.max_seq ) {
376+
val content = replica.read_content(i)
377+
val message_id= replica.get_mid(seq)
378+
if(content == null || message_id == null || !replica.isSidechainComplete(i))
379+
break
380+
e = toFrontendObject(fid, i, message_id, content)
381+
if (e != null)
382+
eval("b2f_new_in_order_event($e)")
383+
frontend_frontier.edit().putInt(fid.toHex(), i + 1).apply()
384+
}
385+
}
359386
}
360387

361-
fun sendToFrontend(fid: ByteArray, seq: Int, mid: ByteArray, payload: ByteArray) {
362-
Log.d("wai", "sendToFrontend seq=${seq} ${payload.toHex()}")
388+
fun toFrontendObject(fid: ByteArray, seq: Int, mid: ByteArray, payload: ByteArray): String? {
363389
val bodyList = Bipf.decode(payload)
364390
if (bodyList == null || bodyList.typ != BIPF_LIST) {
365-
Log.d("sendToFrontend", "decoded payload == null")
366-
return
391+
Log.d("toFrontendObject", "decoded payload == null")
392+
return null
367393
}
368394
val param = Bipf.bipf_list2JSON(bodyList)
369395
var hdr = JSONObject()
370396
hdr.put("fid", "@" + fid.toBase64() + ".ed25519")
371397
hdr.put("ref", mid.toBase64())
372398
hdr.put("seq", seq)
373-
var cmd = "b2f_new_event({header:${hdr.toString()},"
374-
cmd += "public:${param.toString()}"
375-
cmd += "});"
376-
Log.d("CMD", cmd)
377-
eval(cmd)
399+
return "{header:${hdr.toString()}, public:${param.toString()}}"
378400
}
379401

380402

android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/tssb/Replica.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,11 @@ class Replica(val context: MainActivity, val datapath: File, val fid: ByteArray)
185185
val fct = { buf: ByteArray, fid: ByteArray?, _: String? -> context.tinyNode.incoming_pkt(buf,fid!!) }
186186
context.tinyDemux.arm_dmx(new_dmx, fct, fid)
187187

188+
val (_, sz) = Bipf.varint_decode(pkt, DMX_LEN + 1, DMX_LEN + 4)
189+
val content = pkt.sliceArray(8 + sz until 36)
190+
191+
context.wai.sendIncompleteEntryToFrontend(fid, seq, (nam + pkt).sha256().sliceArray(0 until HASH_LEN), content)
192+
188193
if(sendToFront)
189194
context.wai.sendTinyEventToFrontend(fid, seq, (nam + pkt).sha256().sliceArray(0 until HASH_LEN), read_content(seq)!!)
190195
return true
@@ -446,4 +451,9 @@ class Replica(val context: MainActivity, val datapath: File, val fid: ByteArray)
446451
Log.d("replica", "write success, len: ${log_entry.size}")
447452
return seq
448453
}
454+
455+
fun isSidechainComplete(seq: Int): Boolean {
456+
return !state.pend_sc.containsKey(seq)
457+
}
458+
449459
}

android/tinySSB/app/src/main/java/nz/scuttlebutt/tremolavossbol/tssb/Repo.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ class Repo(val context: MainActivity) {
303303
frontier.delete()
304304
frontier.createNewFile()
305305
frontier.appendBytes(new_state.toWire())
306+
context.wai.frontend_frontier.edit().putInt(f.name, new_state.max_pos + 1).apply()
306307

307308
Files.move(new_log.toPath(), File(feed_dir, "log.bin").toPath(), StandardCopyOption.ATOMIC_MOVE)
308309
File(feed_dir, "log").delete()

0 commit comments

Comments
 (0)