mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2026-05-26 17:55:20 +02:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b35868a68 | |||
| d15dcb3725 | |||
| f25f27348b | |||
| c046619b8b |
@@ -207,7 +207,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
ApiMethods.UserAgent = "Grayjay Android (${BuildConfig.VERSION_CODE})";
|
||||
|
||||
Thread.setDefaultUncaughtExceptionHandler { _, throwable ->
|
||||
@@ -249,6 +249,8 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
Logger.i(TAG, "MainActivity Starting");
|
||||
ApiMethods.initCache(cacheDir);
|
||||
|
||||
StateApp.instance.setGlobalContext(this, lifecycleScope);
|
||||
StateApp.instance.mainAppStarting(this);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.futo.polycentric.core.getClaimIfValid
|
||||
import com.futo.polycentric.core.getValidClaims
|
||||
import com.google.protobuf.ByteString
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
@@ -56,83 +57,102 @@ class PolycentricCache {
|
||||
|
||||
private val _taskGetProfile = BatchedTaskHandler<PublicKey, CachedPolycentricProfile>(_scope,
|
||||
{ system ->
|
||||
val signedEventsList = ApiMethods.getQueryLatest(
|
||||
SERVER,
|
||||
system.toProto(),
|
||||
listOf(
|
||||
ContentType.BANNER.value,
|
||||
ContentType.AVATAR.value,
|
||||
ContentType.USERNAME.value,
|
||||
ContentType.DESCRIPTION.value,
|
||||
ContentType.STORE.value,
|
||||
ContentType.SERVER.value,
|
||||
ContentType.STORE_DATA.value,
|
||||
ContentType.PROMOTION_BANNER.value,
|
||||
ContentType.PROMOTION.value,
|
||||
ContentType.MEMBERSHIP_URLS.value,
|
||||
ContentType.DONATION_DESTINATIONS.value
|
||||
)
|
||||
).eventsList.map { e -> SignedEvent.fromProto(e) };
|
||||
|
||||
val signedProfileEvents = signedEventsList.groupBy { e -> e.event.contentType }
|
||||
.map { (_, events) -> events.maxBy { it.event.unixMilliseconds ?: 0 } };
|
||||
|
||||
val storageSystemState = StorageTypeSystemState.create()
|
||||
for (signedEvent in signedProfileEvents) {
|
||||
storageSystemState.update(signedEvent.event)
|
||||
}
|
||||
|
||||
val signedClaimEvents = ApiMethods.getQueryIndex(
|
||||
SERVER,
|
||||
system.toProto(),
|
||||
ContentType.CLAIM.value,
|
||||
limit = 200
|
||||
).eventsList.map { e -> SignedEvent.fromProto(e) };
|
||||
|
||||
val ownedClaims: ArrayList<OwnedClaim> = arrayListOf()
|
||||
for (signedEvent in signedClaimEvents) {
|
||||
if (signedEvent.event.contentType != ContentType.CLAIM.value) {
|
||||
continue;
|
||||
coroutineScope {
|
||||
// Launch concurrent requests for getQueryLatest and getQueryIndex
|
||||
val signedEventsDeferred = async {
|
||||
ApiMethods.getQueryLatest(
|
||||
SERVER,
|
||||
system.toProto(),
|
||||
listOf(
|
||||
ContentType.BANNER.value,
|
||||
ContentType.AVATAR.value,
|
||||
ContentType.USERNAME.value,
|
||||
ContentType.DESCRIPTION.value,
|
||||
ContentType.STORE.value,
|
||||
ContentType.SERVER.value,
|
||||
ContentType.STORE_DATA.value,
|
||||
ContentType.PROMOTION_BANNER.value,
|
||||
ContentType.PROMOTION.value,
|
||||
ContentType.MEMBERSHIP_URLS.value,
|
||||
ContentType.DONATION_DESTINATIONS.value
|
||||
)
|
||||
).eventsList.map { e -> SignedEvent.fromProto(e) }
|
||||
}
|
||||
|
||||
val response = ApiMethods.getQueryReferences(
|
||||
SERVER,
|
||||
Protocol.Reference.newBuilder()
|
||||
.setReference(signedEvent.toPointer().toProto().toByteString())
|
||||
.setReferenceType(2)
|
||||
.build(),
|
||||
null,
|
||||
Protocol.QueryReferencesRequestEvents.newBuilder()
|
||||
.setFromType(ContentType.VOUCH.value)
|
||||
.build()
|
||||
);
|
||||
|
||||
val ownedClaim = response.itemsList.map { SignedEvent.fromProto(it.event) }.getClaimIfValid(signedEvent);
|
||||
if (ownedClaim != null) {
|
||||
ownedClaims.add(ownedClaim);
|
||||
val signedClaimEventsDeferred = async {
|
||||
ApiMethods.getQueryIndex(
|
||||
SERVER,
|
||||
system.toProto(),
|
||||
ContentType.CLAIM.value,
|
||||
limit = 200
|
||||
).eventsList.map { e -> SignedEvent.fromProto(e) }
|
||||
}
|
||||
}
|
||||
|
||||
Logger.i(TAG, "Retrieved profile (ownedClaims = $ownedClaims)");
|
||||
val systemState = SystemState.fromStorageTypeSystemState(storageSystemState);
|
||||
return@BatchedTaskHandler CachedPolycentricProfile(PolycentricProfile(system, systemState, ownedClaims));
|
||||
// Await both requests concurrently
|
||||
val signedEventsList = signedEventsDeferred.await()
|
||||
val signedClaimEvents = signedClaimEventsDeferred.await()
|
||||
|
||||
// Process profile events
|
||||
val signedProfileEvents = signedEventsList
|
||||
.groupBy { it.event.contentType }
|
||||
.map { (_, events) -> events.maxByOrNull { it.event.unixMilliseconds ?: 0 } }
|
||||
.filterNotNull()
|
||||
|
||||
val storageSystemState = StorageTypeSystemState.create().apply {
|
||||
signedProfileEvents.forEach { update(it.event) }
|
||||
}
|
||||
|
||||
// Launch concurrent requests for getQueryReferences
|
||||
val ownedClaimsDeferred = signedClaimEvents.mapNotNull { signedEvent ->
|
||||
if (signedEvent.event.contentType != ContentType.CLAIM.value) {
|
||||
null
|
||||
} else {
|
||||
async {
|
||||
try {
|
||||
val response = ApiMethods.getQueryReferences(
|
||||
SERVER,
|
||||
Protocol.Reference.newBuilder()
|
||||
.setReference(signedEvent.toPointer().toProto().toByteString())
|
||||
.setReferenceType(2)
|
||||
.build(),
|
||||
null,
|
||||
Protocol.QueryReferencesRequestEvents.newBuilder()
|
||||
.setFromType(ContentType.VOUCH.value)
|
||||
.build()
|
||||
)
|
||||
response.itemsList
|
||||
.map { SignedEvent.fromProto(it.event) }
|
||||
.getClaimIfValid(signedEvent)
|
||||
} catch (e: Exception) {
|
||||
Logger.e(TAG, "Failed to get query references for ${signedEvent.toPointer()}", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}.filterNotNull()
|
||||
|
||||
val ownedClaims = ownedClaimsDeferred.mapNotNull { it.await() }.toCollection(ArrayList())
|
||||
|
||||
Logger.i(TAG, "Retrieved profile (ownedClaims = $ownedClaims)")
|
||||
|
||||
val systemState = SystemState.fromStorageTypeSystemState(storageSystemState)
|
||||
CachedPolycentricProfile(PolycentricProfile(system, systemState, ownedClaims))
|
||||
}
|
||||
},
|
||||
{ system -> return@BatchedTaskHandler getCachedProfile(system); },
|
||||
{ system, result ->
|
||||
synchronized(_cache) {
|
||||
_profileCache[system] = result;
|
||||
_profileCache[system] = result
|
||||
|
||||
if (result.profile != null) {
|
||||
for (claim in result.profile.ownedClaims) {
|
||||
val urls = claim.claim.resolveChannelUrls();
|
||||
for (url in urls)
|
||||
_profileUrlCache.map[url] = result;
|
||||
result.profile?.ownedClaims?.forEach { claim ->
|
||||
claim.claim.resolveChannelUrls().forEach { url ->
|
||||
_profileUrlCache.map[url] = result
|
||||
}
|
||||
}
|
||||
|
||||
_profileUrlCache.save();
|
||||
_profileUrlCache.save()
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
private val _batchTaskGetClaims = BatchedTaskHandler<PlatformID, CachedOwnedClaims>(_scope,
|
||||
{ id ->
|
||||
|
||||
@@ -44,9 +44,11 @@ import com.futo.polycentric.core.toBase64
|
||||
import com.futo.polycentric.core.toURLInfoSystemLinkUrl
|
||||
import com.google.protobuf.ByteString
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import userpackage.Protocol
|
||||
import userpackage.Protocol.Reference
|
||||
@@ -510,67 +512,88 @@ class StatePolycentric {
|
||||
};
|
||||
}
|
||||
|
||||
private suspend fun mapQueryReferences(contextUrl: String, response: Protocol.QueryReferencesResponse): List<PolycentricPlatformComment> {
|
||||
return response.itemsList.mapNotNull {
|
||||
val sev = SignedEvent.fromProto(it.event);
|
||||
val ev = sev.event;
|
||||
if (ev.contentType != ContentType.POST.value) {
|
||||
return@mapNotNull null;
|
||||
}
|
||||
private suspend fun mapQueryReferences(contextUrl: String, response: Protocol.QueryReferencesResponse): List<PolycentricPlatformComment> = coroutineScope {
|
||||
response.itemsList.map { item ->
|
||||
async {
|
||||
val sev = SignedEvent.fromProto(item.event)
|
||||
val ev = sev.event
|
||||
if (ev.contentType != ContentType.POST.value) {
|
||||
return@async null
|
||||
}
|
||||
|
||||
try {
|
||||
val post = Protocol.Post.parseFrom(ev.content);
|
||||
val likes = it.countsList[0];
|
||||
val dislikes = it.countsList[1];
|
||||
val replies = it.countsList[2];
|
||||
try {
|
||||
val post = Protocol.Post.parseFrom(ev.content)
|
||||
val likes = item.countsList.getOrNull(0)
|
||||
val dislikes = item.countsList.getOrNull(1)
|
||||
val replies = item.countsList.getOrNull(2)
|
||||
|
||||
val profileEvents = ApiMethods.getQueryLatest(
|
||||
PolycentricCache.SERVER,
|
||||
ev.system.toProto(),
|
||||
listOf(
|
||||
ContentType.AVATAR.value,
|
||||
ContentType.USERNAME.value
|
||||
)
|
||||
).eventsList.map { e -> SignedEvent.fromProto(e) }.groupBy { e -> e.event.contentType }
|
||||
.map { (_, events) -> events.maxBy { x -> x.event.unixMilliseconds ?: 0 } };
|
||||
val profileEvents = ApiMethods.getQueryLatest(
|
||||
PolycentricCache.SERVER,
|
||||
ev.system.toProto(),
|
||||
listOf(
|
||||
ContentType.AVATAR.value,
|
||||
ContentType.USERNAME.value
|
||||
)
|
||||
).eventsList.map { e -> SignedEvent.fromProto(e) }.groupBy { e -> e.event.contentType }
|
||||
.map { (_, events) -> events.maxBy { x -> x.event.unixMilliseconds ?: 0 } };
|
||||
|
||||
val nameEvent = profileEvents.firstOrNull { e -> e.event.contentType == ContentType.USERNAME.value };
|
||||
val avatarEvent = profileEvents.firstOrNull { e -> e.event.contentType == ContentType.AVATAR.value };
|
||||
val imageBundle = if (avatarEvent != null) {
|
||||
val lwwElementValue = avatarEvent.event.lwwElement?.value;
|
||||
if (lwwElementValue != null) {
|
||||
Protocol.ImageBundle.parseFrom(lwwElementValue)
|
||||
val nameEvent = profileEvents.firstOrNull { e -> e.event.contentType == ContentType.USERNAME.value };
|
||||
val avatarEvent = profileEvents.firstOrNull { e -> e.event.contentType == ContentType.AVATAR.value };
|
||||
val imageBundle = if (avatarEvent != null) {
|
||||
val lwwElementValue = avatarEvent.event.lwwElement?.value;
|
||||
if (lwwElementValue != null) {
|
||||
Protocol.ImageBundle.parseFrom(lwwElementValue)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
|
||||
|
||||
val unixMilliseconds = ev.unixMilliseconds
|
||||
//TODO: Don't use single hardcoded server here
|
||||
val systemLinkUrl = ev.system.systemToURLInfoSystemLinkUrl(listOf(PolycentricCache.SERVER))
|
||||
val dp_25 = 25.dp(StateApp.instance.context.resources)
|
||||
|
||||
PolycentricPlatformComment(
|
||||
contextUrl = contextUrl,
|
||||
author = PlatformAuthorLink(
|
||||
id = PlatformID(
|
||||
"polycentric",
|
||||
systemLinkUrl,
|
||||
null,
|
||||
ClaimType.POLYCENTRIC.value.toInt()
|
||||
),
|
||||
name = nameEvent?.event?.lwwElement?.value?.decodeToString() ?: "Unknown",
|
||||
url = systemLinkUrl,
|
||||
thumbnail = imageBundle?.selectBestImage(dp_25 * dp_25)?.let { img ->
|
||||
img.toURLInfoSystemLinkUrl(
|
||||
ev.system.toProto(),
|
||||
img.process,
|
||||
listOf(PolycentricCache.SERVER)
|
||||
)
|
||||
},
|
||||
subscribers = null
|
||||
),
|
||||
msg = if (post.content.length > PolycentricPlatformComment.MAX_COMMENT_SIZE) {
|
||||
post.content.substring(0, PolycentricPlatformComment.MAX_COMMENT_SIZE)
|
||||
} else {
|
||||
post.content
|
||||
},
|
||||
rating = RatingLikeDislikes(likes ?: 0, dislikes ?: 0),
|
||||
date = unixMilliseconds?.let {
|
||||
Instant.ofEpochMilli(it).atOffset(ZoneOffset.UTC)
|
||||
} ?: OffsetDateTime.MIN,
|
||||
replyCount = replies?.toInt() ?: 0,
|
||||
eventPointer = sev.toPointer(),
|
||||
parentReference = sev.event.references.getOrNull(0)
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
null
|
||||
}
|
||||
|
||||
val unixMilliseconds = ev.unixMilliseconds
|
||||
//TODO: Don't use single hardcoded sderver here
|
||||
val systemLinkUrl = ev.system.systemToURLInfoSystemLinkUrl(listOf(PolycentricCache.SERVER));
|
||||
val dp_25 = 25.dp(StateApp.instance.context.resources)
|
||||
return@mapNotNull PolycentricPlatformComment(
|
||||
contextUrl = contextUrl,
|
||||
author = PlatformAuthorLink(
|
||||
id = PlatformID("polycentric", systemLinkUrl, null, ClaimType.POLYCENTRIC.value.toInt()),
|
||||
name = nameEvent?.event?.lwwElement?.value?.decodeToString() ?: "Unknown",
|
||||
url = systemLinkUrl,
|
||||
thumbnail = imageBundle?.selectBestImage(dp_25 * dp_25)?.let { img -> img.toURLInfoSystemLinkUrl(ev.system.toProto(), img.process, listOf(PolycentricCache.SERVER)) },
|
||||
subscribers = null
|
||||
),
|
||||
msg = if (post.content.count() > PolycentricPlatformComment.MAX_COMMENT_SIZE) post.content.substring(0, PolycentricPlatformComment.MAX_COMMENT_SIZE) else post.content,
|
||||
rating = RatingLikeDislikes(likes, dislikes),
|
||||
date = if (unixMilliseconds != null) Instant.ofEpochMilli(unixMilliseconds).atOffset(ZoneOffset.UTC) else OffsetDateTime.MIN,
|
||||
replyCount = replies.toInt(),
|
||||
eventPointer = sev.toPointer(),
|
||||
parentReference = sev.event.references.getOrNull(0)
|
||||
);
|
||||
} catch (e: Throwable) {
|
||||
return@mapNotNull null;
|
||||
}
|
||||
};
|
||||
}.awaitAll().filterNotNull()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
+1
-1
Submodule dep/polycentricandroid updated: f7d58c6ca6...c91b426cee
Reference in New Issue
Block a user