Refactors Ammolite Filters to be regular ones and creates a PerRelayFilter for the use on Amethyst.

This commit is contained in:
Vitor Pamplona 2024-08-07 11:40:01 -04:00
parent 2b1e3cfc93
commit 07e5132943
29 changed files with 346 additions and 210 deletions

View File

@ -39,10 +39,10 @@ import com.vitorpamplona.ammolite.relays.BundledUpdate
import com.vitorpamplona.ammolite.relays.Client
import com.vitorpamplona.ammolite.relays.Constants
import com.vitorpamplona.ammolite.relays.FeedType
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.Relay
import com.vitorpamplona.ammolite.relays.RelaySetupInfo
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.crypto.KeyPair
import com.vitorpamplona.quartz.encoders.ATag
import com.vitorpamplona.quartz.encoders.HexKey
@ -1126,7 +1126,7 @@ class Account(
listOf(
TypedFilter(
setOf(FeedType.FOLLOWS, FeedType.PRIVATE_DMS, FeedType.GLOBAL),
Filter(
PerRelayFilter(
ids = listOf(it.id),
),
),

View File

@ -32,9 +32,9 @@ import com.vitorpamplona.amethyst.ui.actions.relays.updated
import com.vitorpamplona.amethyst.ui.note.combineWith
import com.vitorpamplona.amethyst.ui.note.toShortenHex
import com.vitorpamplona.ammolite.relays.BundledUpdate
import com.vitorpamplona.ammolite.relays.EOSETime
import com.vitorpamplona.ammolite.relays.Relay
import com.vitorpamplona.ammolite.relays.RelayBriefInfoCache
import com.vitorpamplona.ammolite.relays.filters.EOSETime
import com.vitorpamplona.quartz.encoders.ATag
import com.vitorpamplona.quartz.encoders.Hex
import com.vitorpamplona.quartz.encoders.HexKey

View File

@ -29,8 +29,8 @@ import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource
import com.vitorpamplona.amethyst.service.checkNotInMainThread
import com.vitorpamplona.amethyst.ui.note.toShortenHex
import com.vitorpamplona.ammolite.relays.BundledUpdate
import com.vitorpamplona.ammolite.relays.EOSETime
import com.vitorpamplona.ammolite.relays.Relay
import com.vitorpamplona.ammolite.relays.filters.EOSETime
import com.vitorpamplona.quartz.encoders.Hex
import com.vitorpamplona.quartz.encoders.HexKey
import com.vitorpamplona.quartz.encoders.Lud06

View File

@ -26,11 +26,11 @@ import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.service.relays.EOSEAccount
import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES
import com.vitorpamplona.ammolite.relays.Client
import com.vitorpamplona.ammolite.relays.EOSETime
import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.Relay
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.EOSETime
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.encoders.HexKey
import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent
import com.vitorpamplona.quartz.events.BadgeAwardEvent
@ -81,7 +81,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(ContactListEvent.KIND),
authors = listOf(account.userProfile().pubkeyHex),
limit = 1,
@ -92,7 +92,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(MetadataEvent.KIND),
authors = listOf(account.userProfile().pubkeyHex),
limit = 1,
@ -103,7 +103,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
StatusEvent.KIND,
@ -124,7 +124,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") {
return TypedFilter(
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
MetadataEvent.KIND,
@ -146,7 +146,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(BookmarkListEvent.KIND, PeopleListEvent.KIND, MuteListEvent.KIND, BadgeProfilesEvent.KIND, EmojiPackSelectionEvent.KIND),
authors = listOf(account.userProfile().pubkeyHex),
limit = 100,
@ -157,7 +157,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(DraftEvent.KIND, ReportEvent.KIND),
authors = listOf(account.userProfile().pubkeyHex),
since =
@ -172,7 +172,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
authors = listOf(account.userProfile().pubkeyHex),
limit = 400,
),
@ -189,7 +189,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") {
return TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
TextNoteEvent.KIND,
@ -222,7 +222,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") {
return TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
GitReplyEvent.KIND,
@ -244,7 +244,7 @@ object NostrAccountDataSource : AmethystNostrDataSource("AccountData") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(GiftWrapEvent.KIND),
tags = mapOf("p" to listOf(account.userProfile().pubkeyHex)),
since =

View File

@ -25,8 +25,8 @@ import com.vitorpamplona.amethyst.model.Channel
import com.vitorpamplona.amethyst.model.LiveActivitiesChannel
import com.vitorpamplona.amethyst.model.PublicChatChannel
import com.vitorpamplona.ammolite.relays.FeedType
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.events.ChannelMessageEvent
import com.vitorpamplona.quartz.events.LiveActivitiesChatMessageEvent
@ -58,7 +58,7 @@ object NostrChannelDataSource : AmethystNostrDataSource("ChatroomFeed") {
return TypedFilter(
types = setOf(FeedType.FOLLOWS, FeedType.PRIVATE_DMS, FeedType.GLOBAL, FeedType.SEARCH),
filter =
Filter(
PerRelayFilter(
kinds = listOf(ChannelMessageEvent.KIND),
authors = listOf(myAccount.userProfile().pubkeyHex),
limit = 50,
@ -71,7 +71,7 @@ object NostrChannelDataSource : AmethystNostrDataSource("ChatroomFeed") {
return TypedFilter(
types = setOf(FeedType.FOLLOWS, FeedType.PRIVATE_DMS, FeedType.GLOBAL, FeedType.SEARCH),
filter =
Filter(
PerRelayFilter(
kinds = listOf(LiveActivitiesChatMessageEvent.KIND),
authors = listOf(myAccount.userProfile().pubkeyHex),
limit = 50,
@ -86,7 +86,7 @@ object NostrChannelDataSource : AmethystNostrDataSource("ChatroomFeed") {
return TypedFilter(
types = setOf(FeedType.PUBLIC_CHATS),
filter =
Filter(
PerRelayFilter(
kinds = listOf(ChannelMessageEvent.KIND),
tags = mapOf("e" to listOfNotNull(channel?.idHex)),
limit = 200,
@ -96,7 +96,7 @@ object NostrChannelDataSource : AmethystNostrDataSource("ChatroomFeed") {
return TypedFilter(
types = setOf(FeedType.PUBLIC_CHATS),
filter =
Filter(
PerRelayFilter(
kinds = listOf(LiveActivitiesChatMessageEvent.KIND),
tags = mapOf("a" to listOfNotNull(channel?.idHex)),
limit = 200,

View File

@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.service
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.service.relays.EOSEAccount
import com.vitorpamplona.ammolite.relays.FeedType
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.events.ChatroomKey
import com.vitorpamplona.quartz.events.PrivateDmEvent
@ -50,7 +50,7 @@ object NostrChatroomDataSource : AmethystNostrDataSource("ChatroomFeed") {
TypedFilter(
types = setOf(FeedType.PRIVATE_DMS),
filter =
Filter(
PerRelayFilter(
kinds = listOf(PrivateDmEvent.KIND),
authors = myPeer.users.toList(),
tags = mapOf("p" to listOf(account.userProfile().pubkeyHex)),
@ -73,7 +73,7 @@ object NostrChatroomDataSource : AmethystNostrDataSource("ChatroomFeed") {
TypedFilter(
types = setOf(FeedType.PRIVATE_DMS),
filter =
Filter(
PerRelayFilter(
kinds = listOf(PrivateDmEvent.KIND),
authors = listOf(account.userProfile().pubkeyHex),
tags = mapOf("p" to myPeer.users.map { it }),

View File

@ -24,8 +24,8 @@ import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.service.relays.EOSEAccount
import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES
import com.vitorpamplona.ammolite.relays.FeedType
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.events.ChannelCreateEvent
import com.vitorpamplona.quartz.events.ChannelMessageEvent
import com.vitorpamplona.quartz.events.ChannelMetadataEvent
@ -41,7 +41,7 @@ object NostrChatroomListDataSource : AmethystNostrDataSource("MailBoxFeed") {
TypedFilter(
types = setOf(FeedType.PRIVATE_DMS),
filter =
Filter(
PerRelayFilter(
kinds = listOf(PrivateDmEvent.KIND),
tags = mapOf("p" to listOf(account.userProfile().pubkeyHex)),
since =
@ -56,7 +56,7 @@ object NostrChatroomListDataSource : AmethystNostrDataSource("MailBoxFeed") {
TypedFilter(
types = setOf(FeedType.PRIVATE_DMS),
filter =
Filter(
PerRelayFilter(
kinds = listOf(PrivateDmEvent.KIND),
authors = listOf(account.userProfile().pubkeyHex),
since =
@ -71,7 +71,7 @@ object NostrChatroomListDataSource : AmethystNostrDataSource("MailBoxFeed") {
TypedFilter(
types = setOf(FeedType.PUBLIC_CHATS),
filter =
Filter(
PerRelayFilter(
kinds = listOf(ChannelCreateEvent.KIND, ChannelMetadataEvent.KIND),
authors = listOf(account.userProfile().pubkeyHex),
since =
@ -91,7 +91,7 @@ object NostrChatroomListDataSource : AmethystNostrDataSource("MailBoxFeed") {
// Metadata comes from any relay
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(ChannelCreateEvent.KIND),
ids = followingEvents.toList(),
since =
@ -113,7 +113,7 @@ object NostrChatroomListDataSource : AmethystNostrDataSource("MailBoxFeed") {
// Metadata comes from any relay
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(ChannelMetadataEvent.KIND),
tags = mapOf("e" to listOf(it)),
limit = 1,
@ -131,7 +131,7 @@ object NostrChatroomListDataSource : AmethystNostrDataSource("MailBoxFeed") {
TypedFilter(
types = setOf(FeedType.PUBLIC_CHATS),
filter =
Filter(
PerRelayFilter(
kinds = listOf(ChannelMessageEvent.KIND),
tags = mapOf("e" to listOf(it)),
since =

View File

@ -22,8 +22,8 @@ package com.vitorpamplona.amethyst.service
import com.vitorpamplona.amethyst.model.AddressableNote
import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.events.CommunityDefinitionEvent
import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent
@ -38,7 +38,7 @@ object NostrCommunityDataSource : AmethystNostrDataSource("SingleCommunityFeed")
return TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
authors =
community
.moderators()

View File

@ -24,8 +24,8 @@ import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.service.relays.EOSEAccount
import com.vitorpamplona.ammolite.relays.FeedType
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.events.AppDefinitionEvent
import com.vitorpamplona.quartz.events.ChannelCreateEvent
import com.vitorpamplona.quartz.events.ChannelMessageEvent
@ -83,7 +83,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
Filter(
PerRelayFilter(
authors = follows,
kinds = listOf(ClassifiedsEvent.KIND),
limit = 300,
@ -98,7 +98,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
Filter(
PerRelayFilter(
kinds = listOf(ClassifiedsEvent.KIND),
tags =
mapOf(
@ -120,7 +120,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
Filter(
PerRelayFilter(
kinds = listOf(ClassifiedsEvent.KIND),
tags =
mapOf(
@ -146,7 +146,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
Filter(
PerRelayFilter(
kinds = listOf(AppDefinitionEvent.KIND),
limit = 300,
tags = mapOf("k" to kTags),
@ -169,7 +169,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
Filter(
PerRelayFilter(
authors = follows,
kinds = listOf(LiveActivitiesChatMessageEvent.KIND, LiveActivitiesEvent.KIND),
limit = 300,
@ -184,7 +184,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
Filter(
PerRelayFilter(
tags = mapOf("p" to it),
kinds = listOf(LiveActivitiesEvent.KIND),
limit = 100,
@ -210,7 +210,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
TypedFilter(
types = setOf(FeedType.PUBLIC_CHATS),
filter =
Filter(
PerRelayFilter(
authors = follows,
kinds = listOf(ChannelMessageEvent.KIND),
limit = 500,
@ -225,7 +225,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
TypedFilter(
types = setOf(FeedType.PUBLIC_CHATS),
filter =
Filter(
PerRelayFilter(
ids = followChats,
kinds = listOf(ChannelCreateEvent.KIND, ChannelMessageEvent.KIND),
limit = 300,
@ -251,7 +251,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
return TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
Filter(
PerRelayFilter(
authors = follows,
kinds = listOf(CommunityDefinitionEvent.KIND, CommunityPostApprovalEvent.KIND),
limit = 300,
@ -275,7 +275,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
return TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
Filter(
PerRelayFilter(
kinds = listOf(LiveActivitiesChatMessageEvent.KIND, LiveActivitiesEvent.KIND),
tags =
mapOf(
@ -305,7 +305,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
return TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
Filter(
PerRelayFilter(
kinds = listOf(LiveActivitiesChatMessageEvent.KIND, LiveActivitiesEvent.KIND),
tags =
mapOf(
@ -335,7 +335,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
return TypedFilter(
types = setOf(FeedType.PUBLIC_CHATS),
filter =
Filter(
PerRelayFilter(
kinds =
listOf(ChannelCreateEvent.KIND, ChannelMetadataEvent.KIND, ChannelMessageEvent.KIND),
tags =
@ -366,7 +366,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
return TypedFilter(
types = setOf(FeedType.PUBLIC_CHATS),
filter =
Filter(
PerRelayFilter(
kinds =
listOf(ChannelCreateEvent.KIND, ChannelMetadataEvent.KIND, ChannelMessageEvent.KIND),
tags =
@ -397,7 +397,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
return TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
Filter(
PerRelayFilter(
kinds = listOf(CommunityDefinitionEvent.KIND, CommunityPostApprovalEvent.KIND),
tags =
mapOf(
@ -427,7 +427,7 @@ object NostrDiscoveryDataSource : AmethystNostrDataSource("DiscoveryFeed") {
return TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
Filter(
PerRelayFilter(
kinds = listOf(CommunityDefinitionEvent.KIND, CommunityPostApprovalEvent.KIND),
tags =
mapOf(

View File

@ -21,8 +21,8 @@
package com.vitorpamplona.amethyst.service
import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.events.AudioHeaderEvent
import com.vitorpamplona.quartz.events.AudioTrackEvent
import com.vitorpamplona.quartz.events.ChannelMessageEvent
@ -43,7 +43,7 @@ object NostrGeohashDataSource : AmethystNostrDataSource("SingleGeoHashFeed") {
return TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
tags =
mapOf(
"g" to

View File

@ -21,8 +21,8 @@
package com.vitorpamplona.amethyst.service
import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.events.AudioHeaderEvent
import com.vitorpamplona.quartz.events.AudioTrackEvent
import com.vitorpamplona.quartz.events.ChannelMessageEvent
@ -43,7 +43,7 @@ object NostrHashtagDataSource : AmethystNostrDataSource("SingleHashtagFeed") {
return TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
tags =
mapOf(
"t" to

View File

@ -24,8 +24,8 @@ import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.service.relays.EOSEAccount
import com.vitorpamplona.ammolite.relays.FeedType
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent
import com.vitorpamplona.quartz.events.AudioHeaderEvent
import com.vitorpamplona.quartz.events.AudioTrackEvent
@ -82,7 +82,7 @@ object NostrHomeDataSource : AmethystNostrDataSource("HomeFeed") {
return TypedFilter(
types = setOf(if (follows == null) FeedType.GLOBAL else FeedType.FOLLOWS),
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
TextNoteEvent.KIND,
@ -118,7 +118,7 @@ object NostrHomeDataSource : AmethystNostrDataSource("HomeFeed") {
TypedFilter(
types = setOf(FeedType.FOLLOWS),
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
MetadataEvent.KIND,
@ -145,7 +145,7 @@ object NostrHomeDataSource : AmethystNostrDataSource("HomeFeed") {
return TypedFilter(
types = setOf(FeedType.FOLLOWS),
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
TextNoteEvent.KIND,
@ -184,7 +184,7 @@ object NostrHomeDataSource : AmethystNostrDataSource("HomeFeed") {
return TypedFilter(
types = setOf(FeedType.FOLLOWS),
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
TextNoteEvent.KIND,
@ -223,7 +223,7 @@ object NostrHomeDataSource : AmethystNostrDataSource("HomeFeed") {
return TypedFilter(
types = setOf(FeedType.FOLLOWS),
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
TextNoteEvent.KIND,

View File

@ -21,8 +21,8 @@
package com.vitorpamplona.amethyst.service
import com.vitorpamplona.ammolite.relays.FeedType
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.events.LnZapPaymentResponseEvent
import com.vitorpamplona.quartz.signers.NostrSigner
@ -39,7 +39,7 @@ class NostrLnZapPaymentResponseDataSource(
return TypedFilter(
types = feedTypes,
filter =
Filter(
PerRelayFilter(
kinds = listOf(LnZapPaymentResponseEvent.KIND),
authors = listOf(fromServiceHex),
tags =

View File

@ -22,8 +22,8 @@ package com.vitorpamplona.amethyst.service
import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES
import com.vitorpamplona.ammolite.relays.FeedType
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.crypto.KeyPair
import com.vitorpamplona.quartz.encoders.ATag
import com.vitorpamplona.quartz.encoders.Hex
@ -95,7 +95,7 @@ object NostrSearchEventOrUserDataSource : AmethystNostrDataSource("SearchEventFe
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(MetadataEvent.KIND, aTag.kind),
authors = listOfNotNull(aTag.pubKeyHex),
// just to be sure
@ -110,7 +110,7 @@ object NostrSearchEventOrUserDataSource : AmethystNostrDataSource("SearchEventFe
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
ids = listOfNotNull(hexToWatch),
),
),
@ -118,7 +118,7 @@ object NostrSearchEventOrUserDataSource : AmethystNostrDataSource("SearchEventFe
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(MetadataEvent.KIND),
authors = listOfNotNull(hexToWatch),
// just to be sure
@ -135,7 +135,7 @@ object NostrSearchEventOrUserDataSource : AmethystNostrDataSource("SearchEventFe
TypedFilter(
types = setOf(FeedType.SEARCH),
filter =
Filter(
PerRelayFilter(
kinds = listOf(MetadataEvent.KIND),
search = mySearchString,
limit = 1000,
@ -144,7 +144,7 @@ object NostrSearchEventOrUserDataSource : AmethystNostrDataSource("SearchEventFe
TypedFilter(
types = setOf(FeedType.SEARCH),
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
TextNoteEvent.KIND,
@ -165,7 +165,7 @@ object NostrSearchEventOrUserDataSource : AmethystNostrDataSource("SearchEventFe
TypedFilter(
types = setOf(FeedType.SEARCH),
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
ChannelMetadataEvent.KIND,

View File

@ -25,8 +25,8 @@ import com.vitorpamplona.amethyst.model.LiveActivitiesChannel
import com.vitorpamplona.amethyst.model.PublicChatChannel
import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES
import com.vitorpamplona.ammolite.relays.FeedType
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.events.ChannelCreateEvent
import com.vitorpamplona.quartz.events.ChannelMetadataEvent
@ -44,7 +44,7 @@ object NostrSingleChannelDataSource : AmethystNostrDataSource("SingleChannelFeed
return TypedFilter(
types = setOf(FeedType.PUBLIC_CHATS),
filter =
Filter(
PerRelayFilter(
kinds = listOf(ChannelMetadataEvent.KIND),
tags = mapOf("e" to reactionsToWatch),
),
@ -65,7 +65,7 @@ object NostrSingleChannelDataSource : AmethystNostrDataSource("SingleChannelFeed
return TypedFilter(
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(ChannelCreateEvent.KIND),
ids = interestedEvents.toList(),
),
@ -88,7 +88,7 @@ object NostrSingleChannelDataSource : AmethystNostrDataSource("SingleChannelFeed
TypedFilter(
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(aTag.kind),
tags = mapOf("d" to listOf(aTag.dTag)),
authors = listOf(aTag.pubKeyHex),

View File

@ -23,10 +23,10 @@ package com.vitorpamplona.amethyst.service
import com.vitorpamplona.amethyst.model.AddressableNote
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.ammolite.relays.EOSETime
import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.EOSETime
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent
import com.vitorpamplona.quartz.events.DeletionEvent
import com.vitorpamplona.quartz.events.GenericRepostEvent
@ -67,7 +67,7 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") {
TypedFilter(
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
TextNoteEvent.KIND,
@ -89,7 +89,7 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") {
TypedFilter(
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
DeletionEvent.KIND,
@ -117,7 +117,7 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") {
TypedFilter(
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(aTag.kind),
authors = listOf(aTag.pubKeyHex),
limit = 5,
@ -127,7 +127,7 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") {
TypedFilter(
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(aTag.kind),
tags = mapOf("d" to listOf(aTag.dTag)),
authors = listOf(aTag.pubKeyHex),
@ -150,7 +150,7 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") {
TypedFilter(
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
TextNoteEvent.KIND,
@ -173,7 +173,7 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") {
TypedFilter(
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
DeletionEvent.KIND,
@ -200,7 +200,7 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") {
TypedFilter(
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(TextNoteEvent.KIND),
tags = mapOf("q" to it.map { it.idHex }),
since = findMinimumEOSEs(it),
@ -232,7 +232,7 @@ object NostrSingleEventDataSource : AmethystNostrDataSource("SingleEventFeed") {
TypedFilter(
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
ids = interestedEvents.toList(),
),
),

View File

@ -21,10 +21,10 @@
package com.vitorpamplona.amethyst.service
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.ammolite.relays.EOSETime
import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.EOSETime
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent
import com.vitorpamplona.quartz.events.ChatMessageRelayListEvent
import com.vitorpamplona.quartz.events.MetadataEvent
@ -45,7 +45,7 @@ object NostrSingleUserDataSource : AmethystNostrDataSource("SingleUserFeed") {
TypedFilter(
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(MetadataEvent.KIND, AdvertisedRelayListEvent.KIND),
authors = firstTimers,
),
@ -69,7 +69,7 @@ object NostrSingleUserDataSource : AmethystNostrDataSource("SingleUserFeed") {
TypedFilter(
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(MetadataEvent.KIND, StatusEvent.KIND, AdvertisedRelayListEvent.KIND, ChatMessageRelayListEvent.KIND),
authors = groupIds,
since = minEOSEs,
@ -78,7 +78,7 @@ object NostrSingleUserDataSource : AmethystNostrDataSource("SingleUserFeed") {
TypedFilter(
types = EVENT_FINDER_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(ReportEvent.KIND),
tags = mapOf("p" to groupIds),
since = minEOSEs,

View File

@ -22,8 +22,8 @@ package com.vitorpamplona.amethyst.service
import com.vitorpamplona.amethyst.model.ThreadAssembler
import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
object NostrThreadDataSource : AmethystNostrDataSource("SingleThreadFeed") {
private var eventToWatch: String? = null
@ -45,7 +45,7 @@ object NostrThreadDataSource : AmethystNostrDataSource("SingleThreadFeed") {
return TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
ids = eventsToLoad.toList(),
),
)

View File

@ -22,8 +22,8 @@ package com.vitorpamplona.amethyst.service
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.events.AppRecommendationEvent
import com.vitorpamplona.quartz.events.AudioHeaderEvent
import com.vitorpamplona.quartz.events.AudioTrackEvent
@ -56,7 +56,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(MetadataEvent.KIND),
authors = listOf(it.pubkeyHex),
limit = 1,
@ -69,7 +69,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds =
listOf(
TextNoteEvent.KIND,
@ -94,7 +94,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(LnZapEvent.KIND),
tags = mapOf("p" to listOf(it.pubkeyHex)),
limit = 200,
@ -107,7 +107,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(ContactListEvent.KIND),
authors = listOf(it.pubkeyHex),
limit = 1,
@ -120,7 +120,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(ContactListEvent.KIND),
tags = mapOf("p" to listOf(it.pubkeyHex)),
),
@ -132,7 +132,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(BadgeProfilesEvent.KIND),
authors = listOf(it.pubkeyHex),
limit = 1,
@ -145,7 +145,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds =
listOf(BookmarkListEvent.KIND, PeopleListEvent.KIND, AppRecommendationEvent.KIND),
authors = listOf(it.pubkeyHex),
@ -159,7 +159,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds =
listOf(ProfileGalleryEntryEvent.KIND),
authors = listOf(it.pubkeyHex),
@ -173,7 +173,7 @@ object NostrUserProfileDataSource : AmethystNostrDataSource("UserProfileFeed") {
TypedFilter(
types = COMMON_FEED_TYPES,
filter =
Filter(
PerRelayFilter(
kinds = listOf(BadgeAwardEvent.KIND),
tags = mapOf("p" to listOf(it.pubkeyHex)),
limit = 20,

View File

@ -24,8 +24,8 @@ import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.service.relays.EOSEAccount
import com.vitorpamplona.ammolite.relays.FeedType
import com.vitorpamplona.ammolite.relays.Filter
import com.vitorpamplona.ammolite.relays.TypedFilter
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
import com.vitorpamplona.quartz.events.FileHeaderEvent
import com.vitorpamplona.quartz.events.FileStorageHeaderEvent
import com.vitorpamplona.quartz.events.VideoHorizontalEvent
@ -72,7 +72,7 @@ object NostrVideoDataSource : AmethystNostrDataSource("VideoFeed") {
return TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
Filter(
PerRelayFilter(
authors = follows,
kinds = listOf(FileHeaderEvent.KIND, FileStorageHeaderEvent.KIND, VideoHorizontalEvent.KIND, VideoVerticalEvent.KIND),
limit = 200,
@ -97,7 +97,7 @@ object NostrVideoDataSource : AmethystNostrDataSource("VideoFeed") {
return TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
Filter(
PerRelayFilter(
kinds = listOf(FileHeaderEvent.KIND, FileStorageHeaderEvent.KIND, VideoHorizontalEvent.KIND, VideoVerticalEvent.KIND),
tags =
mapOf(
@ -128,7 +128,7 @@ object NostrVideoDataSource : AmethystNostrDataSource("VideoFeed") {
return TypedFilter(
types = setOf(FeedType.GLOBAL),
filter =
Filter(
PerRelayFilter(
kinds = listOf(FileHeaderEvent.KIND, FileStorageHeaderEvent.KIND, VideoHorizontalEvent.KIND, VideoVerticalEvent.KIND),
tags =
mapOf(

View File

@ -21,7 +21,7 @@
package com.vitorpamplona.amethyst.service.relays
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.ammolite.relays.EOSETime
import com.vitorpamplona.ammolite.relays.filters.EOSETime
class EOSERelayList(
var relayList: Map<String, EOSETime> = emptyMap(),

View File

@ -1009,7 +1009,7 @@ fun AmethystClickableIcon() {
fun debugState(context: Context) {
Client
.allSubscriptions()
.forEach { Log.d("STATE DUMP", "${it.key} ${it.value.joinToString { it.filter.toJson() }}") }
.forEach { Log.d("STATE DUMP", "${it.key} ${it.value.joinToString { it.filter.toDebugJson() }}") }
NostrAccountDataSource.printCounter()
NostrChannelDataSource.printCounter()

View File

@ -1,103 +0,0 @@
/**
* Copyright (c) 2024 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.ammolite.relays
import com.vitorpamplona.quartz.events.Event
class Filter(
val ids: List<String>? = null,
val authors: List<String>? = null,
val kinds: List<Int>? = null,
val tags: Map<String, List<String>>? = null,
val since: Map<String, EOSETime>? = null,
val until: Long? = null,
val limit: Int? = null,
val search: String? = null,
) {
fun toJson(forRelay: String? = null): String {
val factory = Event.mapper.nodeFactory
val filter =
factory.objectNode().apply {
ids?.run {
replace(
"ids",
factory.arrayNode(ids.size).apply { ids.forEach { add(it) } },
)
}
authors?.run {
replace(
"authors",
factory.arrayNode(authors.size).apply { authors.forEach { add(it) } },
)
}
kinds?.run {
replace(
"kinds",
factory.arrayNode(kinds.size).apply { kinds.forEach { add(it) } },
)
}
tags?.run {
entries.forEach { kv ->
replace(
"#${kv.key}",
factory.arrayNode(kv.value.size).apply { kv.value.forEach { add(it) } },
)
}
}
since?.run {
if (!isEmpty()) {
if (forRelay != null) {
val relaySince = get(forRelay)
if (relaySince != null) {
put("since", relaySince.time)
}
} else {
val jsonObjectSince = factory.objectNode()
entries.forEach { sincePairs ->
jsonObjectSince.put(sincePairs.key, "${sincePairs.value}")
}
put("since", jsonObjectSince)
}
}
}
until?.run { put("until", until) }
limit?.run { put("limit", limit) }
search?.run { put("search", search) }
}
return Event.mapper.writeValueAsString(filter)
}
fun match(
event: Event,
forRelay: String? = null,
): Boolean {
if (ids?.any { event.id == it } == false) return false
if (kinds?.any { event.kind == it } == false) return false
if (authors?.any { event.pubKey == it } == false) return false
tags?.forEach { tag ->
if (!event.tags.any { it.first() == tag.key && it[1] in tag.value }) return false
}
if (event.createdAt !in (since?.get(forRelay)?.time ?: Long.MIN_VALUE)..(until ?: Long.MAX_VALUE)) {
return false
}
return true
}
}

View File

@ -20,7 +20,9 @@
*/
package com.vitorpamplona.ammolite.relays
import com.vitorpamplona.ammolite.relays.filters.PerRelayFilter
class TypedFilter(
val types: Set<FeedType>,
val filter: Filter,
val filter: PerRelayFilter,
)

View File

@ -18,8 +18,11 @@
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.ammolite.relays
package com.vitorpamplona.ammolite.relays.filters
/*
* Wrapper class to allow changing in EOSE without modifying the list it is included within
*/
class EOSETime(
var time: Long,
) {

View File

@ -0,0 +1,38 @@
/**
* Copyright (c) 2024 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.ammolite.relays.filters
import com.vitorpamplona.quartz.events.Event
class Filter(
val ids: List<String>? = null,
val authors: List<String>? = null,
val kinds: List<Int>? = null,
val tags: Map<String, List<String>>? = null,
val since: Long? = null,
val until: Long? = null,
val limit: Int? = null,
val search: String? = null,
) {
fun toJson() = FilterSerializer.toJson(ids, authors, kinds, tags, since, until, limit, search)
fun match(event: Event) = FilterMatcher.match(event, ids, authors, kinds, tags, since, until)
}

View File

@ -0,0 +1,46 @@
/**
* Copyright (c) 2024 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.ammolite.relays.filters
import com.vitorpamplona.quartz.events.Event
object FilterMatcher {
fun match(
event: Event,
ids: List<String>? = null,
authors: List<String>? = null,
kinds: List<Int>? = null,
tags: Map<String, List<String>>? = null,
since: Long? = null,
until: Long? = null,
): Boolean {
if (ids?.any { event.id == it } == false) return false
if (kinds?.any { event.kind == it } == false) return false
if (authors?.any { event.pubKey == it } == false) return false
tags?.forEach { tag ->
if (!event.tags.any { it.first() == tag.key && it[1] in tag.value }) return false
}
if (event.createdAt !in (since ?: Long.MIN_VALUE)..(until ?: Long.MAX_VALUE)) {
return false
}
return true
}
}

View File

@ -0,0 +1,94 @@
/**
* Copyright (c) 2024 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.ammolite.relays.filters
import com.fasterxml.jackson.databind.node.ObjectNode
import com.vitorpamplona.quartz.events.Event
object FilterSerializer {
fun toJsonObject(
ids: List<String>? = null,
authors: List<String>? = null,
kinds: List<Int>? = null,
tags: Map<String, List<String>>? = null,
since: Long? = null,
until: Long? = null,
limit: Int? = null,
search: String? = null,
): ObjectNode {
val factory = Event.mapper.nodeFactory
return factory.objectNode().apply {
ids?.run {
replace(
"ids",
factory.arrayNode(ids.size).apply { ids.forEach { add(it) } },
)
}
authors?.run {
replace(
"authors",
factory.arrayNode(authors.size).apply { authors.forEach { add(it) } },
)
}
kinds?.run {
replace(
"kinds",
factory.arrayNode(kinds.size).apply { kinds.forEach { add(it) } },
)
}
tags?.run {
entries.forEach { kv ->
replace(
"#${kv.key}",
factory.arrayNode(kv.value.size).apply { kv.value.forEach { add(it) } },
)
}
}
since?.run { put("since", since) }
until?.run { put("until", until) }
limit?.run { put("limit", limit) }
search?.run { put("search", search) }
}
}
fun toJson(
ids: List<String>? = null,
authors: List<String>? = null,
kinds: List<Int>? = null,
tags: Map<String, List<String>>? = null,
since: Long? = null,
until: Long? = null,
limit: Int? = null,
search: String? = null,
): String =
Event.mapper.writeValueAsString(
toJsonObject(
ids,
authors,
kinds,
tags,
since,
until,
limit,
search,
),
)
}

View File

@ -0,0 +1,56 @@
/**
* Copyright (c) 2024 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.ammolite.relays.filters
import com.vitorpamplona.quartz.events.Event
class PerRelayFilter(
val ids: List<String>? = null,
val authors: List<String>? = null,
val kinds: List<Int>? = null,
val tags: Map<String, List<String>>? = null,
val since: Map<String, EOSETime>? = null,
val until: Long? = null,
val limit: Int? = null,
val search: String? = null,
) {
fun toJson(forRelay: String) = FilterSerializer.toJson(ids, authors, kinds, tags, since?.get(forRelay)?.time, until, limit, search)
fun match(
event: Event,
forRelay: String? = null,
) = FilterMatcher.match(event, ids, authors, kinds, tags, since?.get(forRelay)?.time, until)
fun toDebugJson(): String {
val factory = Event.mapper.nodeFactory
val obj = FilterSerializer.toJsonObject(ids, authors, kinds, tags, null, until, limit, search)
since?.run {
if (isNotEmpty()) {
val jsonObjectSince = factory.objectNode()
entries.forEach { sincePairs ->
jsonObjectSince.put(sincePairs.key, "${sincePairs.value}")
}
obj.put("since", jsonObjectSince)
}
}
return Event.mapper.writeValueAsString(obj)
}
}