chore: merge the develop branch into master #1
@@ -278,6 +278,7 @@ class Nostr {
|
|||||||
when (val message = notification.message.asEnum()) {
|
when (val message = notification.message.asEnum()) {
|
||||||
is RelayMessageEnum.EventMsg -> {
|
is RelayMessageEnum.EventMsg -> {
|
||||||
val event = message.event
|
val event = message.event
|
||||||
|
val id = message.subscriptionId
|
||||||
|
|
||||||
// Prevent processing duplicate events
|
// Prevent processing duplicate events
|
||||||
if (processedEvent.contains(event.id())) continue
|
if (processedEvent.contains(event.id())) continue
|
||||||
@@ -299,9 +300,18 @@ class Nostr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event.kind().asStd()?.equals(KindStandard.INBOX_RELAYS) == true) {
|
if (event.kind().asStd()?.equals(KindStandard.INBOX_RELAYS) == true) {
|
||||||
|
// Get all gift wrap events for current user
|
||||||
if (isSignedByUser(event = event)) {
|
if (isSignedByUser(event = event)) {
|
||||||
getUserMessages(msgRelayList = event)
|
getUserMessages(msgRelayList = event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Connect to all msg relays for the currently active chat room
|
||||||
|
if (id.startsWith("room-")) {
|
||||||
|
launch {
|
||||||
|
chatRoomAuth(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Cache the relay list for future use
|
// Cache the relay list for future use
|
||||||
setMsgRelay(pubkey = event.author(), event = event)
|
setMsgRelay(pubkey = event.author(), event = event)
|
||||||
}
|
}
|
||||||
@@ -525,6 +535,23 @@ class Nostr {
|
|||||||
setSigner(keys)
|
setSigner(keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getAllCacheMetadata(): Map<PublicKey, Metadata> {
|
||||||
|
try {
|
||||||
|
val filter = Filter().kind(Kind.fromStd(KindStandard.METADATA)).limit(200u)
|
||||||
|
val events = client?.database()?.query(filter)
|
||||||
|
val results = mutableMapOf<PublicKey, Metadata>()
|
||||||
|
|
||||||
|
events?.toVec()?.forEach { event ->
|
||||||
|
val metadata = Metadata.fromJson(event.content())
|
||||||
|
results[event.author()] = metadata
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw IllegalStateException("Failed to get cache metadata: ${e.message}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun fetchMetadataBatch(keys: List<PublicKey>) {
|
suspend fun fetchMetadataBatch(keys: List<PublicKey>) {
|
||||||
try {
|
try {
|
||||||
val limit = keys.size.toULong() * 4u;
|
val limit = keys.size.toULong() * 4u;
|
||||||
@@ -611,7 +638,7 @@ class Nostr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun chatRoomConnect(members: List<PublicKey>) {
|
suspend fun chatRoomConnect(id: Long, members: List<PublicKey>) {
|
||||||
try {
|
try {
|
||||||
members.forEach { member ->
|
members.forEach { member ->
|
||||||
val kind = Kind.fromStd(KindStandard.INBOX_RELAYS)
|
val kind = Kind.fromStd(KindStandard.INBOX_RELAYS)
|
||||||
@@ -620,7 +647,8 @@ class Nostr {
|
|||||||
|
|
||||||
client?.subscribe(
|
client?.subscribe(
|
||||||
target = ReqTarget.auto(listOf(filter)),
|
target = ReqTarget.auto(listOf(filter)),
|
||||||
closeOn = opts
|
closeOn = opts,
|
||||||
|
id = "room-${id}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -628,6 +656,18 @@ class Nostr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun chatRoomAuth(event: Event) {
|
||||||
|
try {
|
||||||
|
val urls = nip17ExtractRelayList(event);
|
||||||
|
for (url in urls) {
|
||||||
|
client?.addRelay(url)
|
||||||
|
client?.connectRelay(url)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw IllegalStateException("Failed to authenticate chat room: ${e.message}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun sendMessage(
|
suspend fun sendMessage(
|
||||||
to: List<PublicKey>,
|
to: List<PublicKey>,
|
||||||
content: String,
|
content: String,
|
||||||
@@ -694,9 +734,13 @@ class Nostr {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (output != null) {
|
if (output != null) {
|
||||||
|
// Keep track of sent events
|
||||||
sentEvents[output.id] = emptyList()
|
sentEvents[output.id] = emptyList()
|
||||||
if (rumor.id() != null) {
|
if (rumor.id() != null) rumorMap[rumor.id()!!] = output.id
|
||||||
rumorMap[rumor.id()!!] = output.id
|
|
||||||
|
// Collect failed outputs
|
||||||
|
output.failed.forEach { (relayUrl, reason) ->
|
||||||
|
println("Failed to send event to relay $relayUrl: $reason")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ class NostrViewModel(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
startMetadataBatchProcessor()
|
startMetadataBatchProcessor()
|
||||||
|
getCacheMetadata()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
@@ -78,10 +79,7 @@ class NostrViewModel(
|
|||||||
private fun showError(message: String) {
|
private fun showError(message: String) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_errorEvents.send(message)
|
_errorEvents.send(message)
|
||||||
|
if (isCreating.value) _isCreating.value = false
|
||||||
if (isCreating.value) {
|
|
||||||
_isCreating.value = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +114,17 @@ class NostrViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getCacheMetadata() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val results = nostr.getAllCacheMetadata()
|
||||||
|
results.forEach { (pubkey, metadata) ->
|
||||||
|
println("Cache metadata for pubkey $pubkey: $metadata")
|
||||||
|
updateMetadata(pubkey, metadata)
|
||||||
|
seenPublicKeys.add(pubkey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun requestMetadata(pubkey: PublicKey) {
|
private fun requestMetadata(pubkey: PublicKey) {
|
||||||
if (seenPublicKeys.add(pubkey)) {
|
if (seenPublicKeys.add(pubkey)) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
@@ -124,6 +133,10 @@ class NostrViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateMetadata(pubkey: PublicKey, metadata: Metadata) {
|
||||||
|
_metadataStore.getOrPut(pubkey) { MutableStateFlow(null) }.value = metadata
|
||||||
|
}
|
||||||
|
|
||||||
fun getMetadata(pubkey: PublicKey): StateFlow<Metadata?> {
|
fun getMetadata(pubkey: PublicKey): StateFlow<Metadata?> {
|
||||||
val flow = _metadataStore.getOrPut(pubkey) { MutableStateFlow(null) }
|
val flow = _metadataStore.getOrPut(pubkey) { MutableStateFlow(null) }
|
||||||
if (flow.value == null) {
|
if (flow.value == null) {
|
||||||
@@ -132,10 +145,6 @@ class NostrViewModel(
|
|||||||
return flow.asStateFlow()
|
return flow.asStateFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateMetadata(pubkey: PublicKey, metadata: Metadata) {
|
|
||||||
_metadataStore.getOrPut(pubkey) { MutableStateFlow(null) }.value = metadata
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun login() {
|
suspend fun login() {
|
||||||
try {
|
try {
|
||||||
getUserSecret()
|
getUserSecret()
|
||||||
@@ -355,7 +364,7 @@ class NostrViewModel(
|
|||||||
val room = getChatRoom(roomId)
|
val room = getChatRoom(roomId)
|
||||||
val members = room.members
|
val members = room.members
|
||||||
|
|
||||||
nostr.chatRoomConnect(members.toList())
|
nostr.chatRoomConnect(roomId, members.toList())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
showError("Error: ${e.message}")
|
showError("Error: ${e.message}")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user