From 04e612d304cfccda635ac0784e0f53a8c19d39be Mon Sep 17 00:00:00 2001
From: Koen <koen@pop-os.localdomain>
Date: Tue, 13 Jun 2023 10:08:36 +0200
Subject: [PATCH] Made generic toBase64Url() function and removed encode() in
 ApiMethods. unixMilliseconds added to Event.

---
 .../futo/polycentric/core/ApiMethodTests.kt   |  2 +-
 .../com/futo/polycentric/core/ApiMethods.kt   | 22 +++----
 .../java/com/futo/polycentric/core/Models.kt  |  6 +-
 .../futo/polycentric/core/ProcessHandle.kt    |  3 +-
 .../java/com/futo/polycentric/core/Utility.kt | 40 +++++++++++
 .../futo/polycentric/protos/protocol.proto    | 66 +++++++++----------
 6 files changed, 89 insertions(+), 50 deletions(-)

diff --git a/app/src/androidTest/java/com/futo/polycentric/core/ApiMethodTests.kt b/app/src/androidTest/java/com/futo/polycentric/core/ApiMethodTests.kt
index 1a4f6fb..cfc09cb 100644
--- a/app/src/androidTest/java/com/futo/polycentric/core/ApiMethodTests.kt
+++ b/app/src/androidTest/java/com/futo/polycentric/core/ApiMethodTests.kt
@@ -16,7 +16,7 @@ class ApiMethodTests {
     @Test
     fun encode() {
         val data = "0801122018505d585836b6eea3772aeda12492ae6b75497ab9a10c6e069294523968ef3b".decodeHex()
-        val d = ApiMethods.encode(data)
+        val d = data.toBase64Url()
         assertEquals("CAESIBhQXVhYNrbuo3cq7aEkkq5rdUl6uaEMbgaSlFI5aO87", d)
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/polycentric/core/ApiMethods.kt b/app/src/main/java/com/futo/polycentric/core/ApiMethods.kt
index b818b22..30b5aa4 100644
--- a/app/src/main/java/com/futo/polycentric/core/ApiMethods.kt
+++ b/app/src/main/java/com/futo/polycentric/core/ApiMethods.kt
@@ -28,7 +28,7 @@ class ApiMethods {
         }
 
         fun getRanges(server: String, system: Protocol.PublicKey): Protocol.RangesForSystem {
-            val systemQuery = encode(system.toByteArray())
+            val systemQuery = system.toByteArray().toBase64Url()
             val path = "/ranges?system=$systemQuery"
             val (_, response, result) = "$server$path".httpGet()
                 .header(Headers.CONTENT_TYPE, "application/octet-stream").response()
@@ -44,8 +44,8 @@ class ApiMethods {
         }
 
         fun getEvents(server: String, system: Protocol.PublicKey, ranges: Protocol.RangesForSystem): Protocol.Events {
-            val systemQuery = encode(system.toByteArray())
-            val rangesQuery = encode(ranges.toByteArray())
+            val systemQuery = system.toByteArray().toBase64Url()
+            val rangesQuery = ranges.toByteArray().toBase64Url()
 
             val path = "/events?system=$systemQuery&ranges=$rangesQuery"
             val (_, response, result) = "$server$path".httpGet()
@@ -61,8 +61,8 @@ class ApiMethods {
         }
 
         fun getResolveClaim(server: String, trustRoot: Protocol.PublicKey, claim: Protocol.Claim): Protocol.Events {
-            val trustRootQuery = encode(trustRoot.toByteArray())
-            val claimQuery = encode(claim.toByteArray())
+            val trustRootQuery = trustRoot.toByteArray().toBase64Url()
+            val claimQuery = claim.toByteArray().toBase64Url()
             val path = "/resolve_claim?claim=$claimQuery&trust_root=$trustRootQuery"
 
             val (_, response, result) = "$server$path".httpGet()
@@ -78,9 +78,9 @@ class ApiMethods {
         }
 
         fun getQueryIndex(server: String, system: Protocol.PublicKey, eventTypes: List<Long>, limit: Int? = null): Protocol.Events {
-            val systemQuery = encode(system.toByteArray())
-            val eventTypesQuery = encode(Protocol.RepeatedUInt64.newBuilder()
-                .addAllNumbers(eventTypes).build().toByteArray())
+            val systemQuery = system.toByteArray().toBase64Url()
+            val eventTypesQuery = Protocol.RepeatedUInt64.newBuilder()
+                .addAllNumbers(eventTypes).build().toByteArray().toBase64Url()
 
             val path = if (limit != null) {
                 "/query_index?system=$systemQuery&event_types=$eventTypesQuery&limit=$limit"
@@ -106,7 +106,7 @@ class ApiMethods {
             if (countLwwElementReferences != null) builder.addAllCountLwwElementReferences(countLwwElementReferences)
             if (countReferences != null) builder.addAllCountReferences(countReferences)
             val query = builder.build()
-            val encodedQuery = encode(query.toByteArray());
+            val encodedQuery = query.toByteArray().toBase64Url()
 
             val path = "/query_references?query=${encodedQuery}"
             val (_, response, result) = "$server$path".httpGet()
@@ -120,9 +120,5 @@ class ApiMethods {
 
             return Protocol.QueryReferencesResponse.parseFrom(result.get())
         }
-
-        fun encode(v: ByteArray): String {
-            return Base64.encodeToString(v, Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP)
-        }
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/polycentric/core/Models.kt b/app/src/main/java/com/futo/polycentric/core/Models.kt
index f184275..e00ce57 100644
--- a/app/src/main/java/com/futo/polycentric/core/Models.kt
+++ b/app/src/main/java/com/futo/polycentric/core/Models.kt
@@ -334,7 +334,8 @@ class Event(
     val lwwElementSet: LWWElementSet?,
     val lwwElement: LWWElement?,
     val references: MutableList<Protocol.Reference>,
-    val indices: Protocol.Indices
+    val indices: Protocol.Indices,
+    val unixMilliseconds: Long?
 ) {
     fun toProto(): Protocol.Event {
         return Protocol.Event.newBuilder()
@@ -378,7 +379,8 @@ class Event(
                 proto.lwwElementSet?.let { LWWElementSet.fromProto(it) },
                 proto.lwwElement?.let { LWWElement.fromProto(it) },
                 proto.referencesList,
-                proto.indices
+                proto.indices,
+                if (proto.hasUnixMilliseconds()) proto.unixMilliseconds else null
             )
         }
     }
diff --git a/app/src/main/java/com/futo/polycentric/core/ProcessHandle.kt b/app/src/main/java/com/futo/polycentric/core/ProcessHandle.kt
index 7e832ac..257c6a5 100644
--- a/app/src/main/java/com/futo/polycentric/core/ProcessHandle.kt
+++ b/app/src/main/java/com/futo/polycentric/core/ProcessHandle.kt
@@ -213,7 +213,8 @@ class ProcessHandle constructor(
             lwwElementSet,
             lwwElement,
             references,
-            processState.indices!!.toProto()
+            processState.indices!!.toProto(),
+            unixMilliseconds = System.currentTimeMillis()
         )
 
         val eventBuffer = event.toProto().toByteArray()
diff --git a/app/src/main/java/com/futo/polycentric/core/Utility.kt b/app/src/main/java/com/futo/polycentric/core/Utility.kt
index fcf177f..418331d 100644
--- a/app/src/main/java/com/futo/polycentric/core/Utility.kt
+++ b/app/src/main/java/com/futo/polycentric/core/Utility.kt
@@ -3,6 +3,7 @@ package com.futo.polycentric.core
 import android.util.Base64
 import userpackage.Protocol
 import userpackage.Protocol.Claim
+import userpackage.Protocol.URLInfoSystemLink
 
 fun ByteArray.toHexString(): String = joinToString(separator = "") { eachByte -> "%02x".format(eachByte) }
 
@@ -17,6 +18,9 @@ fun String.hexStringToByteArray(): ByteArray {
 fun ByteArray.toBase64(): String {
     return Base64.encodeToString(this, Base64.NO_PADDING or Base64.NO_WRAP)
 }
+fun ByteArray.toBase64Url(): String {
+    return Base64.encodeToString(this, Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP)
+}
 
 fun String.base64ToByteArray(): ByteArray {
     return Base64.decode(this, Base64.NO_PADDING or Base64.NO_WRAP)
@@ -76,4 +80,40 @@ fun List<SignedEvent>.getClaimIfValid(claimEvent: SignedEvent): OwnedClaim? {
     }
 
     return null
+}
+
+fun Pointer.toURLInfoEventLinkUrl(servers: Iterable<String>): String {
+    return this.toProto().toURLInfoEventLinkUrl(servers)
+}
+
+fun Protocol.Pointer.toURLInfoEventLinkUrl(servers: Iterable<String>): String {
+    val urlInfo = Protocol.URLInfo.newBuilder()
+        .setUrlType(2)
+        .setBody(Protocol.URLInfoEventLink.newBuilder()
+            .setSystem(system)
+            .setProcess(process)
+            .setLogicalClock(logicalClock)
+            .addAllServers(servers)
+            .build()
+            .toByteString())
+        .build();
+
+    return "polycentric://" + urlInfo.toByteArray().toBase64Url()
+}
+
+fun PublicKey.systemToURLInfoSystemLinkUrl(servers: Iterable<String>): String {
+    return this.toProto().systemToURLInfoSystemLinkUrl(servers)
+}
+
+fun Protocol.PublicKey.systemToURLInfoSystemLinkUrl(servers: Iterable<String>): String {
+    val urlInfo = Protocol.URLInfo.newBuilder()
+        .setUrlType(1)
+        .setBody(URLInfoSystemLink.newBuilder()
+            .setSystem(this)
+            .addAllServers(servers)
+            .build()
+            .toByteString())
+        .build();
+
+    return "polycentric://" + urlInfo.toByteArray().toBase64Url()
 }
\ No newline at end of file
diff --git a/app/src/main/proto/com/futo/polycentric/protos/protocol.proto b/app/src/main/proto/com/futo/polycentric/protos/protocol.proto
index 739628d..f6a28da 100644
--- a/app/src/main/proto/com/futo/polycentric/protos/protocol.proto
+++ b/app/src/main/proto/com/futo/polycentric/protos/protocol.proto
@@ -58,16 +58,17 @@ message BlobSection {
 }
 
 message Event {
-             PublicKey     system          = 1;
-             Process       process         = 2;
-             uint64        logical_clock   = 3;
-             uint64        content_type    = 4;
-             bytes         content         = 5;
-             VectorClock   vector_clock    = 6;
-             Indices       indices         = 7;
-    optional LWWElementSet lww_element_set = 8;
-    optional LWWElement    lww_element     = 9;
-    repeated Reference     references      = 10;
+             PublicKey     system            = 1;
+             Process       process           = 2;
+             uint64        logical_clock     = 3;
+             uint64        content_type      = 4;
+             bytes         content           = 5;
+             VectorClock   vector_clock      = 6;
+             Indices       indices           = 7;
+    optional LWWElementSet lww_element_set   = 8;
+    optional LWWElement    lww_element       = 9;
+    repeated Reference     references        = 10;
+    optional uint64        unix_milliseconds = 11;
 }
 
 message Digest {
@@ -106,26 +107,6 @@ message RangesForSystem {
     repeated RangesForProcess ranges_for_processes = 1;
 }
 
-message URLInfo {
-    // url_type 1 = URLInfoSystemLink
-    // url_type 2 = URLInfoEventLink
-    // url_type 3 = ExportBundle
-    uint64 url_type = 1;
-    bytes  body     = 2;
-}
-
-message URLInfoSystemLink {
-             PublicKey system  = 1;
-    repeated string    servers = 2;
-}
-
-message URLInfoEventLink {
-             PublicKey system        = 1;
-             Process   process       = 2;
-             uint64    logical_clock = 3;
-    repeated string    servers       = 4;
-}
-
 message PrivateKey {
     uint64 key_type = 1;
     bytes  key      = 2;
@@ -143,9 +124,9 @@ message ExportBundle {
 }
 
 message ResultEventsAndRelatedEventsAndCursor {
-    Events result_events  = 1;
-    Events related_events = 2;
-    uint64 cursor         = 3;
+    Events          result_events  = 1;
+    Events          related_events = 2;
+    optional bytes  cursor         = 3;
 }
 
 message Reference {
@@ -242,3 +223,22 @@ message QueryReferencesResponse {
     optional bytes                       cursor         = 3;
 }
 
+message URLInfo {
+    // url_type 1 = URLInfoSystemLink
+    // url_type 2 = URLInfoEventLink
+    // url_type 3 = ExportBundle
+    uint64 url_type = 1;
+    bytes  body     = 2;
+}
+
+message URLInfoSystemLink {
+             PublicKey system  = 1;
+    repeated string    servers = 2;
+}
+
+message URLInfoEventLink {
+             PublicKey system        = 1;
+             Process   process       = 2;
+             uint64    logical_clock = 3;
+    repeated string    servers       = 4;
+}
\ No newline at end of file
-- 
GitLab