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 1a4f6fbdfe273fb549560dc94bd57d47b208e29e..cfc09cbdbf68de2cf20e41eadbfca44f3432df62 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 b818b22e588f35a85b1980c61308985d56042881..30b5aa4b8e45e5f67ce85febc542649a8e9b2fea 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 f1842759076445bf572b971144e128b3ee71caaf..e00ce57db112753a04b5378b875c7b0fcddece9a 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 7e832ac67a5a8edd9741c185a200c25a761a0114..257c6a5353b3a1105073fc78eaffd73215dfd577 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 fcf177fa80788bd7cb1ce7b5b343959a3d8b532a..418331da40b0f07d0a3f0a78c4ebcc8ae9e086be 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 739628d0f1169ddf1e9fb0a44c9d01245e85080e..f6a28dacd767a6c22ee3888ffe532c52551aed55 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