From 7949fc66b211a4dc87f21090f7b9181bd7dbb0a4 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 22 Sep 2025 09:17:54 -0400 Subject: [PATCH 1/4] Fixes test case cast --- .../java/com/vitorpamplona/amethyst/CashuBTest.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/CashuBTest.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/CashuBTest.kt index 200c896d79..8b8627eb5a 100644 --- a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/CashuBTest.kt +++ b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/CashuBTest.kt @@ -25,6 +25,7 @@ import com.vitorpamplona.amethyst.service.cashu.CashuParser import com.vitorpamplona.amethyst.service.cashu.CashuToken import com.vitorpamplona.amethyst.ui.components.GenericLoadable import junit.framework.TestCase.assertEquals +import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.runBlocking import org.junit.Test import org.junit.runner.RunWith @@ -38,7 +39,7 @@ class CashuBTest { @Test() fun parseCashuA() { runBlocking { - val parsed = (CashuParser().parse(cashuTokenA) as GenericLoadable.Loaded>).loaded[0] + val parsed = (CashuParser().parse(cashuTokenA) as GenericLoadable.Loaded>).loaded[0] assertEquals(cashuTokenA, parsed.token) assertEquals("https://8333.space:3338", parsed.mint) @@ -59,7 +60,7 @@ class CashuBTest { @Test() fun parseCashuB() = runBlocking { - val parsed = (CashuParser().parse(cashuTokenB1) as GenericLoadable.Loaded>).loaded + val parsed = (CashuParser().parse(cashuTokenB1) as GenericLoadable.Loaded>).loaded assertEquals(cashuTokenB1, parsed[0].token) assertEquals("http://localhost:3338", parsed[0].mint) @@ -84,7 +85,7 @@ class CashuBTest { @Test() fun parseCashuB2() = runBlocking { - val parsed = (CashuParser().parse(cashuTokenB2) as GenericLoadable.Loaded>).loaded + val parsed = (CashuParser().parse(cashuTokenB2) as GenericLoadable.Loaded>).loaded assertEquals(cashuTokenB2, parsed[0].token) assertEquals("http://lbutlh5lfggq5r7xpiwhrajdl7sxpupgagazxl65w4c5cg72wtofasad.onion:3338", parsed[0].mint) From 7a280a3cde49fa7c6fdcd28e8310864940f61187 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 22 Sep 2025 19:44:51 -0400 Subject: [PATCH 2/4] - Migrates Quartz from Android to CommonMain - Fully converts OpenTimestamp Java codebase to Kotlin, migrating the sync and async HTTP call interfaces to OkHttp and coroutines - Redesigns parsing of relay commands, messages and filters for performance in Jackson. - Starts the use of KotlinX Serialization when speed is not a requirement - Migrates all Jackson field annotations to Kotlin Serialization - Migrates Regex use in Quarts to Kotlin's Regex class - Migrates Base64 from Android to Kotlin - Migrates UUID from Android/Java to Kotlin - Migrates LRUCache usage from Android/Java to Kotlin collections - Migrates all String to bytearray conversions to Kotlin methods - Migrates all System.arraycopy calls to kotlin native ones. - Separates parsing code from the data classes Companion objects - Exposes Rfc3986 normalizations to each platform. - Exposes URI parsing classes to each platform. - Exposes URL Encoders to each platform. - Exposes BigDecimal to each platform. - Exposes the Url Detector to each platform. - Exposes MacInstances to each platform - Exposes Diggest instances to each platform. - Exposes a BitSet to each platform. - Exposes GZip to each platform. - Exposes Secp256k1 to each platform. - Exposes SecureRandom to each platform. - Exposes Time in seconds to each platform. - Exposes the LargeCache to each platform. - Exposes AES CBC and AES GCM encryption/decryption to each platform - Migrate test assertions to Kotlin Tests - Exposes Address class to each platform because of the Parceleable - Creates our own ByteArrayOutputStream. - Removes Lock features inside the Bloomfilters because we don't need data consistency/ - Migrates UserMetadata parser from Jackson to Kotlin serialization - Removes the need for Static methods in each tag. - Adds an event template serializer - Adds KotlinX Datetime to migrate some of the date-based logs - Adds support for LibSodium in the JVM platform - Creates a shared test build for iOS targets - Fixes several usages of Reflection when serializing classes - Fixes a bug on loading RelayDB for the HintBloom filter test - Increases the Bloom filter space to better use hints in the app. - Removes support for iOS in x86 - Creates a Jackson mapper just for NIP-55, which stays in the Android build only. - Keeps the event store in the android build as well. - Removes @Syncronized tags in favor of Mutexes. - Improved sendAndWaitForResponse NostrClient method to properly account for returns from each relay. - Removes the need for GlobalScope and async calls in the downloadFirstEvent method. - Restructures the parser and serialization of the relay messages and commands for performance with Jackson - Removes the dependency on Jackson's error classes across the codebase. - Moves the hint to quote tag extension methods to their own packages. - Speeds up the generation of Bech32 addresses - Migrates NIP-6 and Blossom uploads to use Kotlin Serialization --- amethyst/build.gradle | 3 + .../com/vitorpamplona/amethyst/CashuBTest.kt | 2 +- .../amethyst/DMFileDecryptionTest.kt | 4 +- .../amethyst/ImageUploadTesting.kt | 9 +- .../vitorpamplona/amethyst/OkHttpOtsTest.kt | 79 +- .../ThreadDualAxisChartAssemblerTest.kt | 47 +- .../vitorpamplona/amethyst/URIParserTest.kt | 2 +- .../notifications/PushDistributorHandler.kt | 2 +- .../notifications/PushMessageReceiver.kt | 2 +- .../components/SelectNotificationProvider.kt | 2 +- .../components/TranslatableRichTextViewer.kt | 2 +- .../com/vitorpamplona/amethyst/Amethyst.kt | 2 +- .../com/vitorpamplona/amethyst/AppModules.kt | 10 +- .../com/vitorpamplona/amethyst/DebugUtils.kt | 2 +- .../amethyst/LocalPreferences.kt | 203 +- .../vitorpamplona/amethyst/model/Account.kt | 38 +- .../model/AccountSyncedSettingsInternal.kt | 6 + .../amethyst/model/AntiSpamFilter.kt | 6 +- .../vitorpamplona/amethyst/model/Channel.kt | 2 +- .../amethyst/model/HashtagIcon.kt | 2 +- .../amethyst/model}/LargeSoftCache.kt | 3 +- .../amethyst/model/LocalCache.kt | 45 +- .../vitorpamplona/amethyst/model/MiniFhir.kt | 5 +- .../com/vitorpamplona/amethyst/model/Note.kt | 6 +- .../amethyst/model/ThreadAssembler.kt | 2 +- .../amethyst/model/UiSettings.kt | 2 + .../com/vitorpamplona/amethyst/model/User.kt | 2 +- .../model/accountsCache/AccountCacheState.kt | 2 +- .../edits/PrivateStorageRelayListState.kt | 2 +- .../model/emphChat/EphemeralChatListState.kt | 2 +- .../nip01UserMetadata/UserMetadataState.kt | 2 +- .../model/nip02FollowLists/FollowListState.kt | 2 +- .../IncomingOtsEventVerifier.kt | 11 +- .../amethyst/model/nip03Timestamp/OtsState.kt | 4 +- .../TorAwareOkHttpOtsResolverBuilder.kt | 54 + .../model/nip11RelayInfo/LoadRelayInfo.kt | 2 +- .../model/nip11RelayInfo/Nip11Retriever.kt | 2 +- .../model/nip17Dms/DmRelayListState.kt | 2 +- .../nip28PublicChats/PublicChatChannel.kt | 4 +- .../nip28PublicChats/PublicChatListState.kt | 2 +- .../model/nip30CustomEmojis/EmojiPackState.kt | 2 +- .../blockedRelays/BlockedRelayListState.kt | 2 +- .../geohashLists/GeohashListState.kt | 2 +- .../hashtagLists/HashtagListState.kt | 2 +- .../nip51Lists/muteList/MuteListState.kt | 2 +- .../searchRelays/SearchRelayListState.kt | 2 +- .../trustedRelays/TrustedRelayListState.kt | 2 +- .../LiveActivitiesChannel.kt | 4 +- .../nip65RelayList/Nip65RelayListState.kt | 2 +- .../nip72Communities/CommunityListState.kt | 2 +- .../nip78AppSpecific/AppSpecificState.kt | 11 +- .../observables/LatestByKindAndAuthor.kt | 2 +- .../preferences/AccountPreferenceStores.kt | 2 +- .../AccountSecretsEncryptedStores.kt | 2 +- .../model/preferences/EncryptedDataStore.kt | 6 +- .../model/preferences/TorSharedPreferences.kt | 3 +- .../model/preferences/UISharedPreferences.kt | 2 +- .../model/privateChats/ChatroomList.kt | 2 +- .../model/serverList/MergedServerListState.kt | 4 +- .../AllFollowsByOutboxTopNavFilter.kt | 2 +- .../AllFollowsByProxyTopNavFilter.kt | 2 +- .../AllCommunitiesTopNavFilter.kt | 2 +- .../community/SingleCommunityTopNavFilter.kt | 2 +- .../SingleCommunityTopNavPerRelayFilter.kt | 2 +- .../amethyst/service/CachedRichTextParser.kt | 2 +- .../amethyst/service/CoroutinesExt.kt | 2 +- .../amethyst/service/EmojiUtils.kt | 2 +- .../amethyst/service/OnlineCheck.kt | 2 +- .../service/connectivity/ConnectivityFlow.kt | 2 +- .../eventCache/MemoryTrimmingService.kt | 2 +- .../service/lnurl/LightningAddressResolver.kt | 2 +- .../location/CachedReversedGeoLocations.kt | 2 +- .../amethyst/service/location/LocationFlow.kt | 2 +- .../service/location/LocationState.kt | 2 +- .../service/location/ReverseGeolocation.kt | 2 +- .../service/logging/ChoreographerHelper.kt | 2 +- .../amethyst/service/logging/LogMonitor.kt | 2 +- .../EventNotificationConsumer.kt | 3 +- .../service/notifications/PokeyReceiver.kt | 2 +- .../service/notifications/RegisterAccounts.kt | 2 +- .../okhttp/EncryptedBlobInterceptor.kt | 2 +- .../service/okhttp/EncryptionKeyCache.kt | 2 +- .../service/okhttp/LoggingInterceptor.kt | 2 +- .../service/okhttp/OkHttpClientFactory.kt | 2 +- .../playback/composable/GetVideoController.kt | 2 +- .../composable/MediaControllerState.kt | 6 +- .../playback/playerPool/ExoPlayerPool.kt | 2 +- .../playback/playerPool/MediaSessionPool.kt | 2 +- .../playback/service/PlaybackService.kt | 2 +- .../playback/service/PlaybackServiceClient.kt | 2 +- .../service/relayClient/RelayLogger.kt | 2 +- .../relayClient/RelayProxyClientConnector.kt | 2 +- .../authCommand/model/AuthCoordinator.kt | 6 +- .../eoseManagers/BaseEoseManager.kt | 2 +- .../compose/NotifyRequestDialog.kt | 2 +- .../loaders/FilterMissingAddressables.kt | 2 +- .../relayClient/speedLogger/FrameStat.kt | 4 +- .../relayClient/speedLogger/KindGroup.kt | 2 +- .../speedLogger/RelaySpeedLogger.kt | 2 +- .../service/tts/TextToSpeechHelper.kt | 2 +- .../amethyst/service/uploads/EncryptFiles.kt | 2 +- .../amethyst/service/uploads/FileHeader.kt | 2 +- .../service/uploads/MediaCompressor.kt | 8 +- .../service/uploads/MultiOrchestrator.kt | 2 +- .../service/uploads/UploadOrchestrator.kt | 2 +- .../uploads/blossom/BlossomUploader.kt | 23 +- .../service/uploads/nip96/Nip96Uploader.kt | 7 +- .../uploads/nip96/ServerInfoRetriever.kt | 2 +- .../vitorpamplona/amethyst/ui/MainActivity.kt | 3 +- .../amethyst/ui/actions/MediaSaverToDisk.kt | 10 +- .../amethyst/ui/actions/NewMessageTagger.kt | 2 +- .../mediaServers/BlossomServersViewModel.kt | 12 +- .../mediaServers/MediaServerEditField.kt | 2 +- .../mediaServers/NIP96ServersViewModel.kt | 12 +- .../ui/actions/mediaServers/ServerName.kt | 5 +- .../ui/actions/uploads/ShowImageUploadItem.kt | 2 +- .../amethyst/ui/components/ClickableRoute.kt | 4 +- .../ui/components/ExpandableRichTextViewer.kt | 2 +- .../amethyst/ui/components/RichTextViewer.kt | 4 +- .../amethyst/ui/components/ShareHelper.kt | 2 +- .../ui/components/ZoomableContentView.kt | 2 +- .../markdown/RenderContentAsMarkdown.kt | 4 +- .../util/MediaCompressorFileUtils.kt | 6 +- .../amethyst/ui/dal/FilterByListParams.kt | 2 +- .../ui/feeds/ChannelFeedContentState.kt | 2 +- .../amethyst/ui/navigation/AppNavigation.kt | 2 +- .../ui/navigation/drawer/DrawerContent.kt | 4 +- .../vitorpamplona/amethyst/ui/note/Loaders.kt | 2 +- .../amethyst/ui/note/MultiSetCompose.kt | 2 +- .../ui/note/NIP05VerificationDisplay.kt | 4 +- .../amethyst/ui/note/PollNote.kt | 6 +- .../ui/note/UpdateReactionTypeDialog.kt | 2 +- .../amethyst/ui/note/UsernameDisplay.kt | 4 +- .../WatchAndLoadMyEmojiList.kt | 2 +- .../ui/note/elements/DisplayCommunity.kt | 2 +- .../note/elements/DisplayUncitedHashtags.kt | 2 +- .../amethyst/ui/note/types/AppDefinition.kt | 4 +- .../amethyst/ui/note/types/AudioTrack.kt | 2 +- .../amethyst/ui/note/types/CommunityHeader.kt | 4 +- .../amethyst/ui/note/types/Emoji.kt | 2 +- .../amethyst/ui/note/types/Git.kt | 4 +- .../amethyst/ui/note/types/Highlight.kt | 6 +- .../ui/note/types/InteractiveStory.kt | 2 +- .../types/NIP90ContentDiscoveryResponse.kt | 4 +- .../amethyst/ui/note/types/PictureDisplay.kt | 2 +- .../amethyst/ui/note/types/PinList.kt | 2 +- .../amethyst/ui/note/types/Poll.kt | 4 +- .../amethyst/ui/note/types/PrivateMessage.kt | 4 +- .../amethyst/ui/note/types/PublicMessage.kt | 2 +- .../amethyst/ui/note/types/Report.kt | 2 +- .../amethyst/ui/note/types/Text.kt | 4 +- .../ui/note/types/TextModification.kt | 2 +- .../amethyst/ui/note/types/Torrent.kt | 14 +- .../amethyst/ui/note/types/Video.kt | 4 +- .../amethyst/ui/screen/AccountScreen.kt | 2 +- .../ui/screen/AccountStateViewModel.kt | 2 +- .../amethyst/ui/screen/FeedViewModel.kt | 2 +- .../amethyst/ui/screen/FollowListState.kt | 2 +- .../amethyst/ui/screen/UserFeedViewModel.kt | 2 +- .../ui/screen/loggedIn/AccountViewModel.kt | 52 +- .../loggedIn/DecryptAndIndexProcessor.kt | 2 +- .../ui/screen/loggedIn/LoggedInPage.kt | 2 +- .../loggedIn/chats/feed/DrawAuthorInfo.kt | 2 +- .../types/RenderChangeChannelMetadataNote.kt | 2 +- .../feed/types/RenderCreateChannelNote.kt | 6 +- .../chats/feed/types/RenderEncryptedFile.kt | 4 +- .../chats/feed/types/RenderRegularTextNote.kt | 4 +- .../privateDM/dal/ChatroomFeedViewModel.kt | 2 +- .../privateDM/send/ChatNewMessageViewModel.kt | 2 +- .../privateDM/send/upload/ChatFileSender.kt | 2 +- .../privateDM/send/upload/ChatFileUploader.kt | 2 +- .../send/upload/SuccessfulUploads.kt | 2 +- .../nip53LiveActivities/ChannelView.kt | 2 +- .../LiveActivityChannelScreen.kt | 2 +- .../header/LongLiveActivityChannelHeader.kt | 2 +- .../send/ChannelNewMessageViewModel.kt | 3 +- .../loggedIn/communities/CommunityScreen.kt | 2 +- .../nip53LiveActivities/LiveActivityCard.kt | 2 +- .../DiscoverCommunityFeedFilter.kt | 2 +- .../FilterCommunitiesByCommunity.kt | 2 +- .../nip99Classifieds/NewProductViewModel.kt | 2 +- .../loggedIn/home/ShortNotePostViewModel.kt | 2 +- .../notifications/CardFeedContentState.kt | 2 +- .../loggedIn/notifications/CardFeedState.kt | 2 +- .../notifications/NotificationSummaryState.kt | 2 +- .../NewPublicMessageViewModel.kt | 2 +- .../profile/header/DrawAdditionalInfo.kt | 2 +- .../profile/relays/RelayFeedViewModel.kt | 3 +- .../profile/zaps/LnZapFeedViewModel.kt | 2 +- .../screen/loggedIn/qrcode/QrCodeScanner.kt | 2 +- .../loggedIn/relays/RelayInformationScreen.kt | 2 +- .../loggedIn/settings/StringFeedViewModel.kt | 2 +- .../settings/dal/HiddenAccountsFeedFilter.kt | 2 +- .../loggedOff/login/ExternalSignerButton.kt | 2 +- .../amethyst/ui/tor/TorService.kt | 2 +- .../amethyst/ui/tor/TorSettingsFlow.kt | 2 +- amethyst/src/main/res/values/strings.xml | 1 + .../PushNotificationReceiverService.kt | 2 +- .../notifications/PushNotificationUtils.kt | 2 +- .../components/TranslatableRichTextViewer.kt | 2 +- .../amethyst/NewMessageTaggerKeyParseTest.kt | 2 +- .../vitorpamplona/amethyst/UrlDecoderTest.kt | 2 +- .../ui/components/MediaCompressorTest.kt | 2 +- .../ammolite/relays/BundledUpdate.kt | 2 +- benchmark/build.gradle | 2 +- .../benchmark/RichTextParserBenchmark.kt | 6 +- .../benchmark/BaseLargeCacheBenchmark.kt | 8 +- .../quartz/benchmark/BechBenchmark.kt | 2 +- .../quartz/benchmark/CacheBenchmark.kt | 6 +- .../quartz/benchmark/ChaCha20Benchmark.kt | 6 + .../quartz/benchmark/ContainsBenchmark.kt | 2 +- .../quartz/benchmark/EnsureTest.kt | 3 +- .../quartz/benchmark/EventBenchmark.kt | 30 +- .../benchmark/EventCmdHasherBenchmark.kt | 11 +- .../quartz/benchmark/EventVerifySerializer.kt | 6 +- .../quartz/benchmark/GiftWrapBenchmark.kt | 2 +- .../benchmark/GiftWrapReceivingBenchmark.kt | 4 +- .../quartz/benchmark/HintIndexerBenchmark.kt | 9 +- .../quartz/benchmark/HkdfBenchmark.kt | 2 + .../benchmark/LargeDBInsertBenchmark.kt | 10 +- .../benchmark/LargeDBQueryingBenchmark.kt | 2 +- .../quartz/benchmark/Sha256Benchmark.kt | 8 +- .../quartz/benchmark/SignVerifyBenchmark.kt | 2 +- build.gradle | 1 + .../compose/TextFieldValueExtensionTest.kt | 2 +- .../amethyst/commons/preview/BlurhashTest.kt | 4 +- .../ExpandableTextCutOffCalculatorTest.kt | 2 +- .../commons/richtext/RichTextParserTest.kt | 4 +- .../amethyst/commons/emojicoder/EmojiCoder.kt | 4 - .../commons/richtext/RichTextParser.kt | 4 +- .../richtext/RichTextParserSegments.kt | 2 +- .../commons/robohash/RobohashAssembler.kt | 2 +- .../amethyst/commons/Base83Test.kt | 2 +- .../amethyst/commons/SRGBTest.kt | 2 +- gradle.properties | 5 +- gradle/libs.versions.toml | 7 + quartz/build.gradle.kts | 101 +- .../resources => }/relayDB.txt | 0 .../quartz/LargeDBSignatureCheck.kt | 10 +- .../vitorpamplona/quartz/bloom/BloomFilter.kt | 6 +- .../quartz/nip01Core/EventSigCheck.kt | 32 +- .../nip01Core/store/sqlite/BasicTest.kt | 2 +- .../nip01Core/store/sqlite/ExpirationTest.kt | 2 +- .../nip01Core/store/sqlite/LargeDBTests.kt | 6 +- .../quartz/nip03Timestamp/ots/OtsTest.kt | 96 +- .../quartz/nip04Dm/EncryptionTest.kt | 4 +- .../Bip32SeedDerivationTest.kt | 2 +- .../nip06KeyDerivation/Bip39KeyPathTest.kt | 2 +- .../nip06KeyDerivation/Bip39MnemonicsTest.kt | 4 +- .../quartz/nip06KeyDerivation/Nip06Test.kt | 2 +- .../quartz/nip10Notes/CitationTests.kt | 6 +- .../quartz/nip10Notes/ThreadingTests.kt | 2 +- .../quartz/nip17Dm/AESGCMTest.kt | 10 +- .../quartz/nip19Bech32/NIP19EmbedTests.kt | 4 +- .../nip22Comments/GeolocatedComments.kt | 8 +- .../quartz/nip44Encryption/Nip44v2Test.kt | 13 +- .../nip44Encryption/TestPackageClasses.kt | 51 +- .../quartz/nip46RemoteSigner/Nip46Test.kt | 3 +- .../quartz/nip49PrivKeyEnc/NIP49Test.kt | 8 +- .../quartz/nip57Zaps/PrivateZapTests.kt | 4 +- .../nip59GiftWraps/GiftWrapEventTest.kt | 10 +- .../{tags/addressables => core}/Address.kt | 67 +- .../quartz/nip01Core/crypto/EventHasher.kt | 149 - .../quartz/nip01Core/jackson/JsonMapper.kt | 88 - .../relay/commands/toRelay/CountCmd.kt | 66 - .../relay/commands/toRelay/ReqCmd.kt | 69 - .../relay/commands/toRelay/ToRelayParser.kt | 38 - .../relay/filters/FilterSerializer.kt | 95 - .../store/sqlite/EventIndexesModule.kt | 11 +- .../quartz/nip03Timestamp/ots/Utils.kt | 166 -- .../ots/http/BlockstreamExplorer.kt | 80 - .../nip03Timestamp/ots/http/Calendar.kt | 127 - .../ots/http/CalendarAsyncSubmit.kt | 71 - .../quartz/nip03Timestamp/ots/http/Request.kt | 97 - .../nip03Timestamp/ots/http/Response.kt | 88 - .../ots/okhttp/OkHttpCalendar.kt | 138 - .../ots/okhttp/OkHttpCalendarAsyncSubmit.kt | 67 - .../ots/okhttp/OkHttpCalendarBuilder.kt | 37 - .../quartz/nip46RemoteSigner/BunkerRequest.kt | 89 - .../nip46RemoteSigner/BunkerResponse.kt | 105 - .../nip49PrivKeyEnc/SecretKeyOrEmptySpec.kt | 180 -- .../nip55AndroidSigner/JsonMapperNip55.kt | 63 + .../api/background/queries/DecryptZapQuery.kt | 2 +- .../api/background/queries/SignQuery.kt | 4 +- .../background/utils/ContentResolverExt.kt | 2 +- .../api/foreground/IntentRequestManager.kt | 2 +- .../intents/requests/LoginRequest.kt | 4 +- .../intents/responses/SignResponse.kt | 4 +- .../intents/results/IntentResult.kt | 14 +- .../api/permission/Permission.kt | 8 +- .../client/NostrSignerExternal.kt | 3 + ...stance.kt => LibSodiumInstance.android.kt} | 10 +- .../vitorpamplona/quartz/utils/Log.android.kt | 61 + .../quartz/{ => utils}/Platform.android.kt | 4 +- ...stance.kt => Secp256k1Instance.android.kt} | 18 +- .../quartz/utils/UriParser.android.kt | 61 + .../quartz/TestResourceLoader.kt} | 15 +- .../nip01Core/hints/HintIndexerMemoryTest.kt | 38 + .../EventDbQueryAssemblerTest.kt | 2 +- .../vitorpamplona/quartz/utils/RuntimeExt.kt | 6 +- .../nip01Core/hints => resources}/relayDB.txt | 0 .../audio/header/AudioHeaderEvent.kt | 0 .../audio/header/TagArrayBuilderExt.kt | 0 .../audio/header/tags/DownloadUrlTag.kt | 2 - .../audio/header/tags/StreamUrlTag.kt | 2 - .../audio/header/tags/WaveformTag.kt | 9 +- .../audio/track/AudioTrackEvent.kt | 8 +- .../audio/track/TagArrayBuilderExt.kt | 0 .../experimental/audio/track/tags/CoverTag.kt | 2 - .../experimental/audio/track/tags/MediaTag.kt | 2 - .../audio/track/tags/ParticipantTag.kt | 3 - .../experimental/audio/track/tags/PriceTag.kt | 2 - .../experimental/audio/track/tags/TypeTag.kt | 2 - .../bounties/BountyAddValueEvent.kt | 3 +- .../quartz/experimental/bounties/EventExt.kt | 2 +- .../quartz/experimental/bounties/RewardTag.kt | 4 +- .../experimental/bounties/TagArrayExt.kt | 0 .../decoupling/DecoupledCipher.kt | 0 .../decoupling/EncryptionKeyCache.kt | 2 +- .../decoupling/EncryptionKeyDerivation.kt | 2 +- .../setup/EncryptionKeyListEvent.kt | 0 .../decoupling/setup/TagArrayBuilderExt.kt | 0 .../decoupling/setup/tags/KeyTag.kt | 2 - .../edits/TextNoteModificationEvent.kt | 0 .../ephemChat/chat/EphemeralChatEvent.kt | 0 .../experimental/ephemChat/chat/RoomId.kt | 0 .../ephemChat/chat/TagArrayBuilderExt.kt | 0 .../ephemChat/chat/tags/RelayTag.kt | 3 - .../ephemChat/chat/tags/RoomTag.kt | 3 - .../ephemChat/db/EphemeralRoom.kt | 2 +- .../ephemChat/db/EphemeralRoomCache.kt | 2 +- .../ephemChat/list/EphemeralChatListEvent.kt | 2 +- .../ephemChat/list/TagArrayBuilderExt.kt | 0 .../ephemChat/list/TagArrayExt.kt | 0 .../ephemChat/list/tags/RoomIdTag.kt | 4 - .../forks/BaseThreadedEventExt.kt | 2 +- .../experimental/forks/MarkedETagExt.kt | 0 .../inlineMetadata/Nip54InlineMetadata.kt | 34 +- .../InteractiveStoryBaseEvent.kt | 0 .../InteractiveStoryPrologueEvent.kt | 6 +- .../InteractiveStoryReadingStateEvent.kt | 6 +- .../InteractiveStorySceneEvent.kt | 6 +- .../interactiveStories/TagArrayBuilderExt.kt | 2 +- .../interactiveStories/tags/ReadStatusTag.kt | 2 - .../interactiveStories/tags/RootSceneTag.kt | 5 +- .../interactiveStories/tags/StoryOptionTag.kt | 4 +- .../experimental/limits/LimitProcessor.kt | 0 .../quartz/experimental/limits/Limits.kt | 36 +- .../experimental/medical/FhirResourceEvent.kt | 0 .../nip95/data/FileStorageEvent.kt | 6 +- .../nip95/data/TagArrayBuilderExt.kt | 0 .../nip95/header/FileStorageHeaderEvent.kt | 1 + .../nip95/header/TagArrayBuilderExt.kt | 0 .../quartz/experimental/nns/NNSEvent.kt | 0 .../experimental/nns/TagArrayBuilderExt.kt | 0 .../quartz/experimental/nns/tags/IPv4Tag.kt | 2 - .../quartz/experimental/nns/tags/IPv6Tag.kt | 2 - .../experimental/nns/tags/VersionTag.kt | 2 - .../profileGallery/GalleryListEvent.kt | 2 +- .../ProfileGalleryEntryEvent.kt | 0 .../profileGallery/TagArrayBuilderExt.kt | 0 .../publicMessages/PublicMessageEvent.kt | 0 .../publicMessages/TagArrayBuilderExt.kt | 0 .../publicMessages/tags/ReceiverTag.kt | 4 - .../relationshipStatus/ContactCardEvent.kt | 2 +- .../relationshipStatus/TagArrayBuilderExt.kt | 0 .../relationshipStatus/tags/PetNameTag.kt | 2 - .../relationshipStatus/tags/RankTag.kt | 2 - .../relationshipStatus/tags/SummaryTag.kt | 2 - .../experimental/zapPolls/PollNoteEvent.kt | 2 +- .../zapPolls/TagArrayBuilderExt.kt | 0 .../experimental/zapPolls/tags/ClosedAtTag.kt | 2 - .../zapPolls/tags/ConsensusThresholdTag.kt | 2 - .../experimental/zapPolls/tags/MaximumTag.kt | 2 - .../experimental/zapPolls/tags/MinimumTag.kt | 2 - .../zapPolls/tags/PollOptionTag.kt | 2 - .../quartz/lightning/LnInvoiceUtil.kt | 40 +- .../quartz/lightning/LnWithdrawalUtil.kt | 14 +- .../vitorpamplona/quartz/lightning/Lud06.kt | 15 +- .../quartz/nip01Core/core/Address.kt | 52 + .../nip01Core/core/AddressSerializer.kt | 67 + .../quartz/nip01Core/core/AddressableEvent.kt | 3 +- .../nip01Core/core/BaseAddressableEvent.kt | 5 +- .../nip01Core/core/BaseReplaceableEvent.kt | 7 +- .../quartz/nip01Core/core/Event.kt | 11 +- .../quartz/nip01Core/core/HexKey.kt | 0 .../quartz/nip01Core/core/IEvent.kt | 0 .../nip01Core/core}/ImmutableListOfLists.kt | 2 +- .../quartz/nip01Core/core/Kind.kt | 0 .../nip01Core/core/OptimizedJsonMapper.kt | 50 + .../quartz/nip01Core/core/Tag.kt | 0 .../quartz/nip01Core/core/TagArray.kt | 4 +- .../quartz/nip01Core/core/TagArrayBuilder.kt | 4 +- .../nip01Core/crypto/DeterministicSigner.kt | 0 .../quartz/nip01Core/crypto/EventAssembler.kt | 2 +- .../quartz/nip01Core/crypto}/EventExt.kt | 6 +- .../quartz/nip01Core/crypto/EventHasher.kt | 60 + .../nip01Core/crypto/EventHasherSerializer.kt | 44 + .../quartz/nip01Core/crypto/KeyPair.kt | 0 .../quartz/nip01Core/crypto/Nip01.kt | 0 .../quartz/nip01Core/hints/EventHintBundle.kt | 18 - .../quartz/nip01Core/hints/HintIndexer.kt | 21 +- .../quartz/nip01Core/hints/HintProviders.kt | 0 .../quartz/nip01Core/hints/bloom/BitSetExt.kt | 4 +- .../hints/bloom/BloomFilterMurMur3.kt | 33 +- .../nip01Core/hints/bloom/MurmurHash3.kt | 0 .../nip01Core/hints/types/AddressHint.kt | 2 +- .../nip01Core/hints/types/EventIdHint.kt | 0 .../quartz/nip01Core/hints/types/Hint.kt | 0 .../nip01Core/hints/types/PubKeyHint.kt | 0 .../nip01Core/metadata/MetadataEvent.kt | 170 +- .../nip01Core/metadata/TagArrayBuilderExt.kt | 0 .../quartz/nip01Core/metadata/UserMetadata.kt | 11 +- .../nip01Core/metadata/tags/AboutTag.kt | 0 .../nip01Core/metadata/tags/BannerTag.kt | 0 .../nip01Core/metadata/tags/DisplayNameTag.kt | 0 .../nip01Core/metadata/tags/Lud06Tag.kt | 0 .../nip01Core/metadata/tags/Lud16Tag.kt | 0 .../quartz/nip01Core/metadata/tags/NameTag.kt | 0 .../nip01Core/metadata/tags/Nip05Tag.kt | 0 .../nip01Core/metadata/tags/PictureTag.kt | 0 .../nip01Core/metadata/tags/PronounsTag.kt | 0 .../nip01Core/metadata/tags/WebsiteTag.kt | 0 .../nip01Core/relay/client/INostrClient.kt | 0 .../nip01Core/relay/client/NostrClient.kt | 20 +- .../relay/client/NostrClientSubscription.kt | 0 .../client/accessories/EventCollector.kt | 6 +- .../accessories/NostrClientSendAndWaitExt.kt | 84 +- .../NostrClientSingleDownloadExt.kt | 31 +- .../client/accessories/RelayAuthenticator.kt | 6 +- .../RelayInsertConfirmationCollector.kt | 6 +- .../relay/client/accessories/RelayLogger.kt | 6 +- .../relay/client/accessories/RelayNotifier.kt | 4 +- .../client/listeners/IRelayClientListener.kt | 0 .../listeners/RedirectRelayClientListener.kt | 0 .../relay/client/pool/PoolEventOutbox.kt | 0 .../client/pool/PoolEventOutboxRepository.kt | 2 +- .../client/pool/PoolSubscriptionRepository.kt | 2 +- .../relay/client/pool/RelayBasedFilter.kt | 2 +- .../nip01Core/relay/client/pool/RelayPool.kt | 2 +- .../relay/client/single/IRelayClient.kt | 0 .../relay/client/single/Subscription.kt | 0 .../client/single/basic/BasicRelayClient.kt | 50 +- .../relay/client/single/simple/OutboxCache.kt | 2 +- .../client/single/simple/SimpleRelayClient.kt | 0 .../nip01Core/relay/client/stats/RelayStat.kt | 0 .../relay/client/stats/RelayStats.kt | 6 +- .../client/subscriptions/Subscription.kt | 0 .../subscriptions/SubscriptionController.kt | 2 +- .../client/subscriptions/SubscriptionStats.kt | 4 +- .../relay/commands/toClient/AuthMessage.kt | 10 +- .../relay/commands/toClient/ClosedMessage.kt | 13 +- .../relay/commands/toClient/EoseMessage.kt | 10 +- .../relay/commands/toClient/EventMessage.kt | 11 +- .../relay/commands/toClient/Message.kt | 6 +- .../relay/commands/toClient/NoticeMessage.kt | 7 +- .../relay/commands/toClient/NotifyMessage.kt | 10 +- .../relay/commands/toClient/OkMessage.kt | 11 +- .../relay/commands/toRelay/AuthCmd.kt | 13 +- .../relay/commands/toRelay/CloseCmd.kt | 15 +- .../relay/commands/toRelay/Command.kt | 6 +- .../relay/commands/toRelay/CountCmd.kt | 34 + .../relay/commands/toRelay/EventCmd.kt | 13 +- .../relay/commands/toRelay/ReqCmd.kt | 34 + .../quartz/nip01Core/relay/filters/Filter.kt | 10 +- .../nip01Core/relay/filters/FilterMatcher.kt | 0 .../relay/normalizer/NormalizedRelayUrl.kt | 0 .../relay/normalizer/RelayUrlNormalizer.kt | 13 +- .../nip01Core/relay/sockets/WebSocket.kt | 0 .../relay/sockets/WebSocketListener.kt | 0 .../relay/sockets/WebsocketBuilder.kt | 0 .../relay/sockets/WebsocketBuilderFactory.kt | 0 .../quartz/nip01Core/signers/EventTemplate.kt | 11 +- .../quartz/nip01Core/signers/NostrSigner.kt | 2 + .../nip01Core/signers/NostrSignerInternal.kt | 3 + .../nip01Core/signers/NostrSignerSync.kt | 0 .../nip01Core/signers/SignerExceptions.kt | 0 .../nip01Core/signers/caches/CacheResults.kt | 0 .../nip01Core/signers/caches/DecryptCache.kt | 9 +- .../quartz/nip01Core/tags/aTag}/ATag.kt | 37 +- .../quartz/nip01Core/tags/aTag}/EventExt.kt | 2 +- .../tags/aTag}/TagArrayBuilderExt.kt | 7 +- .../nip01Core/tags/aTag}/TagArrayExt.kt | 2 +- .../quartz/nip01Core/tags/dTag}/DTag.kt | 4 +- .../quartz/nip01Core/tags/dTag}/EventExt.kt | 2 +- .../tags/dTag}/TagArrayBuilderExt.kt | 2 +- .../nip01Core/tags/dTag}/TagArrayExt.kt | 2 +- .../quartz/nip01Core/tags/events/ETag.kt | 14 +- .../quartz/nip01Core/tags/events/EventExt.kt | 0 .../nip01Core/tags/events/EventReference.kt | 0 .../nip01Core/tags/events/GenericETag.kt | 0 .../tags/events/TagArrayBuilderExt.kt | 5 - .../nip01Core/tags/events/TagArrayExt.kt | 0 .../quartz/nip01Core/tags/geohash/EventExt.kt | 0 .../nip01Core/tags/geohash/GeoHashTag.kt | 4 - .../tags/geohash/GeohashPrecision.kt | 0 .../tags/geohash/TagArrayBuilderExt.kt | 0 .../nip01Core/tags/geohash/TagArrayExt.kt | 0 .../nip01Core/tags/hashtags/EventExt.kt | 0 .../nip01Core/tags/hashtags/HashtagTag.kt | 2 - .../nip01Core/tags/hashtags/MipMapHashTags.kt | 4 +- .../tags/hashtags/TagArrayBuilderExt.kt | 0 .../nip01Core/tags/hashtags/TagArrayExt.kt | 0 .../quartz/nip01Core/tags/kinds/EventExt.kt | 0 .../quartz/nip01Core/tags/kinds/KindTag.kt | 1 - .../tags/kinds/TagArrayBuilderExt.kt | 0 .../nip01Core/tags/kinds/TagArrayExt.kt | 0 .../quartz/nip01Core/tags/people/EntityExt.kt | 0 .../quartz/nip01Core/tags/people/EventExt.kt | 0 .../quartz/nip01Core/tags/people/PTag.kt | 8 +- .../tags/people/PubKeyReferenceTag.kt | 0 .../tags/people/TagArrayBuilderExt.kt | 0 .../nip01Core/tags/people/TagArrayExt.kt | 0 .../tags/publishedAt/PublishedAtProvider.kt | 0 .../nip01Core/tags/references/EventExt.kt | 0 .../tags/references}/HttpUrlFormatter.kt | 11 +- .../nip01Core/tags/references/ReferenceTag.kt | 7 - .../tags/references/TagArrayBuilderExt.kt | 0 .../nip01Core/tags/references/TagArrayExt.kt | 0 .../nip02FollowList/ContactListEvent.kt | 2 +- .../quartz/nip02FollowList/RelaySet.kt | 11 +- .../quartz/nip02FollowList/tags/ContactTag.kt | 9 +- .../quartz/nip03Timestamp/OtsEvent.kt | 17 +- .../quartz/nip03Timestamp/OtsResolver.kt | 20 +- .../nip03Timestamp/OtsResolverBuilder.kt | 4 - .../nip03Timestamp/TagArrayBuilderExt.kt | 0 .../nip03Timestamp/VerificationState.kt | 0 .../nip03Timestamp/VerificationStateCache.kt | 12 +- .../nip03Timestamp/ots/BitcoinExplorer.kt | 6 +- .../quartz/nip03Timestamp/ots/BlockHeader.kt | 0 .../ots/DetachedTimestampFile.kt | 63 - .../quartz/nip03Timestamp/ots/Hash.kt | 45 - .../quartz/nip03Timestamp/ots/Merkle.kt | 0 .../nip03Timestamp/ots/OpenTimestamps.kt | 150 +- .../nip03Timestamp/ots/OtsBlockHeightCache.kt | 42 + .../quartz/nip03Timestamp/ots/README.md | 0 .../nip03Timestamp/ots/RemoteCalendar.kt | 57 + .../ots/StreamDeserializationContext.kt | 4 +- .../ots/StreamSerializationContext.kt | 0 .../quartz/nip03Timestamp/ots/Timestamp.kt | 47 +- .../quartz/nip03Timestamp/ots/Utils.kt} | 43 +- .../quartz/nip03Timestamp/ots/VerifyResult.kt | 24 +- .../BitcoinBlockHeaderAttestation.kt | 0 .../ots/attestation/PendingAttestation.kt | 27 +- .../ots/attestation/TimeAttestation.kt | 0 .../ots/attestation/UnknownAttestation.kt | 0 .../nip03Timestamp/ots/crypto/Digest.kt | 0 .../ots/crypto/ExtendedDigest.kt | 0 .../ots/crypto/GeneralDigest.kt | 6 +- .../nip03Timestamp/ots/crypto/KeccakDigest.kt | 54 +- .../nip03Timestamp/ots/crypto/Memoable.kt | 0 .../quartz/nip03Timestamp/ots/crypto/Pack.kt | 4 - .../ots/crypto/RIPEMD160Digest.kt | 2 +- .../exceptions/CommitmentNotFoundException.kt | 0 .../exceptions/DeserializationException.kt | 0 .../ots/exceptions/ExceededSizeException.kt | 0 .../ots/exceptions/UrlException.kt | 0 .../ots/exceptions/VerificationException.kt | 0 .../quartz/nip03Timestamp/ots/op/Op.kt | 4 +- .../quartz/nip03Timestamp/ots/op/OpAppend.kt | 3 +- .../quartz/nip03Timestamp/ots/op/OpBinary.kt | 5 +- .../quartz/nip03Timestamp/ots/op/OpCrypto.kt | 47 +- .../nip03Timestamp/ots/op/OpKECCAK256.kt | 0 .../quartz/nip03Timestamp/ots/op/OpPrepend.kt | 3 +- .../nip03Timestamp/ots/op/OpRIPEMD160.kt | 0 .../quartz/nip03Timestamp/ots/op/OpSHA1.kt | 0 .../quartz/nip03Timestamp/ots/op/OpSHA256.kt | 0 .../quartz/nip03Timestamp/ots/op/OpUnary.kt | 2 +- .../nip03Timestamp/tags/TargetEventKindTag.kt | 0 .../nip03Timestamp/tags/TargetEventTag.kt | 0 .../quartz/nip04Dm/PrivateDMCache.kt | 0 .../quartz/nip04Dm/crypto/EncryptedInfo.kt | 12 +- .../quartz/nip04Dm/crypto/Encryption.kt | 5 +- .../quartz/nip04Dm/crypto/Nip04.kt | 0 .../quartz/nip04Dm/messages/PrivateDmEvent.kt | 0 .../nip04Dm/messages/TagArrayBuilderExt.kt | 1 + .../quartz/nip05DnsIdentifiers/Nip05.kt | 35 +- .../nip06KeyDerivation/Bip32SeedDerivation.kt | 12 +- .../quartz/nip06KeyDerivation/Bip39KeyPath.kt | 0 .../nip06KeyDerivation/Bip39Mnemonics.kt | 0 .../quartz/nip06KeyDerivation/Nip06.kt | 0 .../quartz/nip09Deletions/DeletionEvent.kt | 6 +- .../quartz/nip09Deletions/DeletionIndex.kt | 4 +- .../quartz/nip10Notes/BaseNoteEvent.kt | 9 +- .../quartz/nip10Notes/BaseThreadedEvent.kt | 2 +- .../quartz/nip10Notes/TextNoteEvent.kt | 2 +- .../nip10Notes/content/ContentHashTags.kt | 10 +- .../quartz/nip10Notes/content/IndexedTags.kt | 15 +- .../quartz/nip10Notes/content/NostrUris.kt | 0 .../quartz/nip10Notes/content/Urls.kt | 7 +- .../quartz/nip10Notes/tags/MarkedETag.kt | 21 +- .../quartz/nip10Notes/tags/Positional.kt | 0 .../quartz/nip10Notes/tags/ReplyBuilder.kt | 0 .../nip10Notes/tags/TagArrayBuilderExt.kt | 0 .../nip11RelayInfo/Nip11RelayInformation.kt | 19 +- .../vitorpamplona/quartz/nip13Pow/EventExt.kt | 0 .../quartz/nip13Pow/TagArrayBuilderExt.kt | 0 .../quartz/nip13Pow/TagArrayExt.kt | 0 .../quartz/nip13Pow/miner/ByteArrayExt.kt | 0 .../quartz/nip13Pow/miner/MiningBuffer.kt | 2 +- .../quartz/nip13Pow/miner/PoWMiner.kt | 11 +- .../quartz/nip13Pow/miner/PoWRankEvaluator.kt | 4 - .../quartz/nip13Pow/tags/PoWTag.kt | 4 - .../quartz/nip14Subject/EventExt.kt | 0 .../quartz/nip14Subject/SubjectTag.kt | 3 - .../quartz/nip14Subject/TagArrayBuilderExt.kt | 0 .../quartz/nip14Subject/TagArrayExt.kt | 0 .../quartz/nip17Dm/NIP17Factory.kt | 0 .../quartz/nip17Dm/base/BaseDMGroupEvent.kt | 0 .../quartz/nip17Dm/base/ChatroomKey.kt | 0 .../quartz/nip17Dm/base/ChatroomKeyable.kt | 0 .../quartz/nip17Dm/base/NIP17Group.kt | 0 .../ChatMessageEncryptedFileHeaderEvent.kt | 2 +- .../nip17Dm/files/TagArrayBuilderExt.kt | 1 + .../nip17Dm/files/tags/EncryptionAlgo.kt | 3 - .../nip17Dm/files/tags/EncryptionKey.kt | 3 - .../nip17Dm/files/tags/EncryptionNonce.kt | 3 - .../quartz/nip17Dm/files/tags/FileTypeTag.kt | 2 - .../nip17Dm/messages/ChatMessageEvent.kt | 1 + .../nip17Dm/messages/TagArrayBuilderExt.kt | 1 + .../settings/ChatMessageRelayListEvent.kt | 4 +- .../quartz/nip17Dm/settings/tags/RelayTag.kt | 4 - .../quartz/nip18Reposts/GenericRepostEvent.kt | 4 +- .../quartz/nip18Reposts/RepostEvent.kt | 4 +- .../quartz/nip18Reposts/quotes/EntityExt.kt | 2 +- .../quartz/nip18Reposts/quotes/EventExt.kt | 0 .../nip18Reposts/quotes/QAddressableTag.kt | 5 +- .../quartz/nip18Reposts/quotes/QEventTag.kt | 6 +- .../quartz/nip18Reposts/quotes/QTag.kt | 7 +- .../nip18Reposts/quotes/TagArrayBuilderExt.kt | 0 .../quartz/nip18Reposts/quotes/TagArrayExt.kt | 0 .../quartz/nip19Bech32/ATagExt.kt | 4 +- .../quartz/nip19Bech32/ByteArrayExt.kt | 0 .../quartz/nip19Bech32/EventExt.kt | 2 +- .../quartz/nip19Bech32/ListEntityExt.kt | 0 .../quartz/nip19Bech32/Nip19Parser.kt | 65 +- .../quartz/nip19Bech32/TlvBuilderExt.kt | 0 .../quartz/nip19Bech32/TlvTypes.kt | 0 .../quartz/nip19Bech32/bech32/Bech32Util.kt | 12 +- .../quartz/nip19Bech32/entities/Entity.kt | 0 .../quartz/nip19Bech32/entities/NAddress.kt | 4 +- .../quartz/nip19Bech32/entities/NEmbed.kt | 0 .../quartz/nip19Bech32/entities/NEvent.kt | 0 .../quartz/nip19Bech32/entities/NNote.kt | 0 .../quartz/nip19Bech32/entities/NProfile.kt | 0 .../quartz/nip19Bech32/entities/NPub.kt | 0 .../quartz/nip19Bech32/entities/NRelay.kt | 0 .../quartz/nip19Bech32/entities/NSec.kt | 0 .../quartz/nip19Bech32/tlv/Tlv.kt | 25 +- .../quartz/nip19Bech32/tlv/TlvBuilder.kt | 9 +- .../quartz/nip21UriScheme/EventExt.kt | 0 .../quartz/nip22Comments/CommentEvent.kt | 2 +- .../quartz/nip22Comments/RootScope.kt | 0 .../nip22Comments/TagArrayBuilderExt.kt | 0 .../nip22Comments/tags/ReplyAddressTag.kt | 10 +- .../nip22Comments/tags/ReplyAuthorTag.kt | 5 - .../nip22Comments/tags/ReplyEventTag.kt | 9 - .../nip22Comments/tags/ReplyIdentifierTag.kt | 6 - .../quartz/nip22Comments/tags/ReplyKindTag.kt | 10 - .../nip22Comments/tags/RootAddressTag.kt | 12 +- .../nip22Comments/tags/RootAuthorTag.kt | 6 - .../quartz/nip22Comments/tags/RootEventTag.kt | 9 - .../nip22Comments/tags/RootIdentifierTag.kt | 5 - .../quartz/nip22Comments/tags/RootKindTag.kt | 8 - .../nip23LongContent/LongTextNoteEvent.kt | 12 +- .../nip23LongContent/TagArrayBuilderExt.kt | 0 .../quartz/nip23LongContent/tags/ImageTag.kt | 2 - .../nip23LongContent/tags/PublishedAtTag.kt | 2 - .../nip23LongContent/tags/SummaryTag.kt | 2 - .../quartz/nip23LongContent/tags/TitleTag.kt | 2 - .../quartz/nip25Reactions/ReactionEvent.kt | 5 +- .../admin/ChannelCreateEvent.kt | 14 +- .../admin/ChannelHideMessageEvent.kt | 0 .../admin/ChannelMetadataEvent.kt | 12 +- .../admin/ChannelMuteUserEvent.kt | 0 .../base/BasePublicChatEvent.kt | 0 .../nip28PublicChat/base/ChannelData.kt | 11 +- .../base/IsInPublicChatChannel.kt | 0 .../base/TagArrayBuilderExt.kt | 1 + .../nip28PublicChat/list/ChannelListEvent.kt | 2 +- .../list/TagArrayBuilderExt.kt | 0 .../nip28PublicChat/list/TagArrayExt.kt | 0 .../nip28PublicChat/list/tags/ChannelTag.kt | 8 - .../message/ChannelMessageEvent.kt | 2 +- .../quartz/nip30CustomEmoji/CustomEmoji.kt | 31 +- .../quartz/nip30CustomEmoji/EmojiUrlTag.kt | 0 .../quartz/nip30CustomEmoji/EventExt.kt | 0 .../nip30CustomEmoji/TagArrayBuilderExt.kt | 0 .../quartz/nip30CustomEmoji/TagArrayExt.kt | 0 .../nip30CustomEmoji/pack/EmojiPackEvent.kt | 8 +- .../selection/EmojiPackSelectionEvent.kt | 5 +- .../selection/TagArrayBuilderExt.kt | 8 +- .../vitorpamplona/quartz/nip31Alts/AltTag.kt | 3 - .../quartz/nip31Alts/EventExt.kt | 0 .../quartz/nip31Alts/TagArrayBuilderExt.kt | 0 .../quartz/nip31Alts/TagArrayExt.kt | 0 .../quartz/nip34Git/issue/GitIssueEvent.kt | 2 +- .../nip34Git/issue/TagArrayBuilderExt.kt | 3 +- .../quartz/nip34Git/patch/GitPatchEvent.kt | 4 +- .../quartz/nip34Git/reply/GitReplyEvent.kt | 2 +- .../nip34Git/reply/TagArrayBuilderExt.kt | 4 +- .../nip34Git/repository/GitRepositoryEvent.kt | 8 +- .../nip34Git/repository/TagArrayBuilderExt.kt | 0 .../nip34Git/repository/tags/CloneTag.kt | 2 - .../repository/tags/DescriptionTag.kt | 2 - .../nip34Git/repository/tags/NameTag.kt | 2 - .../quartz/nip34Git/repository/tags/WebTag.kt | 2 - .../quartz/nip35Torrents/DefaultTrackers.kt | 0 .../nip35Torrents/TagArrayBuilderExt.kt | 0 .../nip35Torrents/TorrentCommentEvent.kt | 1 + .../quartz/nip35Torrents/TorrentEvent.kt | 31 +- .../quartz/nip35Torrents/tags/BtihTag.kt | 2 - .../quartz/nip35Torrents/tags/FileTag.kt | 3 - .../quartz/nip35Torrents/tags/InfoHashTag.kt | 2 - .../quartz/nip35Torrents/tags/TrackerTag.kt | 2 - .../ContentWarningTag.kt | 4 - .../quartz/nip36SensitiveContent/EventExt.kt | 0 .../TagArrayBuilderExt.kt | 0 .../nip36SensitiveContent/TagArrayExt.kt | 0 .../quartz/nip37Drafts/DraftWrapCache.kt | 0 .../quartz/nip37Drafts/DraftWrapEvent.kt | 11 +- .../quartz/nip37Drafts/ExposeInDraft.kt | 0 .../PrivateOutboxRelayListEvent.kt | 4 +- .../quartz/nip38UserStatus/StatusEvent.kt | 0 .../quartz/nip39ExtIdentities/EventExt.kt | 0 .../nip39ExtIdentities/GitHubIdentity.kt | 0 .../nip39ExtIdentities/IdentityClaimTag.kt | 2 +- .../nip39ExtIdentities/MastodonIdentity.kt | 0 .../nip39ExtIdentities/TagArrayBuilderExt.kt | 0 .../nip39ExtIdentities/TelegramIdentity.kt | 0 .../nip39ExtIdentities/TwitterIdentity.kt | 0 .../nip39ExtIdentities/UnsupportedIdentity.kt | 0 .../quartz/nip40Expiration/EventExt.kt | 0 .../quartz/nip40Expiration/ExpirationTag.kt | 3 - .../nip40Expiration/TagArrayBuilderExt.kt | 0 .../quartz/nip40Expiration/TagArrayExt.kt | 0 .../quartz/nip42RelayAuth/RelayAuthEvent.kt | 0 .../nip42RelayAuth/tags/ChallengeTag.kt | 2 - .../quartz/nip42RelayAuth/tags/RelayTag.kt | 4 - .../nip44Encryption/EncryptedInfoString.kt | 5 +- .../quartz/nip44Encryption/Nip44.kt | 27 +- .../quartz/nip44Encryption/Nip44v1.kt | 13 +- .../quartz/nip44Encryption/Nip44v2.kt | 19 +- .../quartz/nip44Encryption/SharedKeyCache.kt | 2 +- .../quartz/nip44Encryption/crypto/ChaCha20.kt | 4 +- .../quartz/nip44Encryption/crypto/Hkdf.kt | 28 +- .../nip46RemoteSigner/BunkerMessage.kt} | 11 +- .../quartz/nip46RemoteSigner/BunkerRequest.kt | 36 + .../nip46RemoteSigner/BunkerRequestConnect.kt | 6 +- .../BunkerRequestGetPublicKey.kt | 6 +- .../BunkerRequestGetRelays.kt | 6 +- .../BunkerRequestNip04Decrypt.kt | 6 +- .../BunkerRequestNip04Encrypt.kt | 6 +- .../BunkerRequestNip44Decrypt.kt | 6 +- .../BunkerRequestNip44Encrypt.kt | 6 +- .../nip46RemoteSigner/BunkerRequestPing.kt | 6 +- .../nip46RemoteSigner/BunkerRequestSign.kt | 6 +- .../nip46RemoteSigner/BunkerResponse.kt | 36 + .../nip46RemoteSigner/BunkerResponseAck.kt | 6 +- .../BunkerResponseDecrypt.kt | 6 +- .../BunkerResponseEncrypt.kt | 6 +- .../nip46RemoteSigner/BunkerResponseError.kt | 11 +- .../nip46RemoteSigner/BunkerResponseEvent.kt | 6 +- .../BunkerResponseGetRelays.kt | 22 +- .../nip46RemoteSigner/BunkerResponsePong.kt | 6 +- .../BunkerResponsePublicKey.kt | 6 +- .../nip46RemoteSigner/NostrConnectEvent.kt | 8 +- .../LnZapPaymentRequestEvent.kt | 6 +- .../LnZapPaymentResponseEvent.kt | 4 +- .../nip47WalletConnect/Nip47WalletConnect.kt | 17 +- .../NostrWalletConnectRequestCache.kt | 0 .../NostrWalletConnectResponseCache.kt | 0 .../quartz/nip47WalletConnect/Request.kt | 4 +- .../quartz/nip47WalletConnect/Response.kt | 15 +- .../quartz/nip48ProxyTags/EventExt.kt | 0 .../quartz/nip48ProxyTags/ProxyTag.kt | 3 - .../nip48ProxyTags/TagArrayBuilderExt.kt | 0 .../quartz/nip48ProxyTags/TagArrayExt.kt | 0 .../quartz/nip49PrivKeyEnc/ByteArrayExt.kt | 0 .../quartz/nip49PrivKeyEnc/Nip49.kt | 18 +- .../quartz/nip49PrivKeyEnc/PBKDF.kt | 31 +- .../quartz/nip49PrivKeyEnc/SCrypt.kt | 39 +- .../nip50Search/SearchRelayListEvent.kt | 4 +- .../quartz/nip50Search/SearchableEvent.kt | 0 .../quartz/nip51Lists/PinListEvent.kt | 0 .../nip51Lists/PrivateTagArrayBuilder.kt | 0 .../quartz/nip51Lists/PrivateTagArrayEvent.kt | 0 .../nip51Lists/PrivateTagArrayEventCache.kt | 0 .../quartz/nip51Lists/TagArrayExt.kt | 0 .../bookmarkList/BookmarkListEvent.kt | 4 +- .../bookmarkList/TagArrayBuilderExt.kt | 0 .../bookmarkList/tags/AddressBookmark.kt | 16 +- .../bookmarkList/tags/BookmarkIdTag.kt | 0 .../bookmarkList/tags/EventBookmark.kt | 8 - .../nip51Lists/encryption/NostrSignerExt.kt | 0 .../encryption/PrivateTagsInContent.kt | 14 +- .../nip51Lists/followList/FollowListEvent.kt | 14 +- .../followList/TagArrayBuilderExt.kt | 0 .../nip51Lists/followList/TagArrayExt.kt | 0 .../geohashList/GeohashListEvent.kt | 2 +- .../geohashList/TagArrayBuilderExt.kt | 0 .../nip51Lists/geohashList/TagArrayExt.kt | 0 .../hashtagList/HashtagListEvent.kt | 2 +- .../hashtagList/TagArrayBuilderExt.kt | 0 .../nip51Lists/hashtagList/TagArrayExt.kt | 0 .../nip51Lists/muteList/MuteListEvent.kt | 2 +- .../nip51Lists/muteList/TagArrayBuilderExt.kt | 0 .../quartz/nip51Lists/muteList/TagArrayExt.kt | 0 .../nip51Lists/muteList/tags/MuteTag.kt | 0 .../nip51Lists/muteList/tags/UserTag.kt | 4 - .../nip51Lists/muteList/tags/WordTag.kt | 5 - .../nip51Lists/peopleList/PeopleListEvent.kt | 16 +- .../peopleList/TagArrayBuilderExt.kt | 0 .../nip51Lists/peopleList/TagArrayExt.kt | 0 .../relayLists/BlockedRelayListEvent.kt | 4 +- .../relayLists/BroadcastRelayListEvent.kt | 4 +- .../relayLists/IndexerRelayListEvent.kt | 4 +- .../relayLists/ProxyRelayListEvent.kt | 4 +- .../relayLists/TrustedRelayListEvent.kt | 4 +- .../nip51Lists/relayLists/tags/RelayTag.kt | 4 - .../relayLists/tags/TagArrayBuilderExt.kt | 0 .../nip51Lists/relayLists/tags/TagArrayExt.kt | 0 .../nip51Lists/relaySets/RelaySetEvent.kt | 0 .../quartz/nip51Lists/tags/DescriptionTag.kt | 2 - .../quartz/nip51Lists/tags/ImageTag.kt | 2 - .../quartz/nip51Lists/tags/NameTag.kt | 2 - .../quartz/nip51Lists/tags/RelayTag.kt | 4 - .../quartz/nip51Lists/tags/TitleTag.kt | 2 - .../nip52Calendar/CalendarDateSlotEvent.kt | 0 .../quartz/nip52Calendar/CalendarEvent.kt | 0 .../quartz/nip52Calendar/CalendarRSVPEvent.kt | 0 .../nip52Calendar/CalendarTimeSlotEvent.kt | 0 .../chat/LiveActivitiesChatMessageEvent.kt | 4 +- .../chat/TagArrayBuilderExt.kt | 4 +- .../meetingSpaces/MeetingRoomEvent.kt | 0 .../meetingSpaces/MeetingSpaceEvent.kt | 0 .../meetingSpaces/tags/EndpointUrlTag.kt | 2 - .../meetingSpaces/tags/MeetingSpaceTag.kt | 16 +- .../meetingSpaces/tags/RecordingTag.kt | 2 - .../meetingSpaces/tags/RelayListTag.kt | 2 - .../meetingSpaces/tags/RoomNameTag.kt | 2 - .../meetingSpaces/tags/ServiceUrlTag.kt | 2 - .../meetingSpaces/tags/StatusTag.kt | 3 - .../presence/MeetingRoomPresenceEvent.kt | 4 +- .../presence/TagArrayBuilderExt.kt | 1 + .../presence/tags/HandRaisedTag.kt | 2 - .../presence/tags/MeetingRoomTag.kt | 16 +- .../streaming/LiveActivitiesEvent.kt | 0 .../streaming/tags/CurrentParticipantsTag.kt | 2 - .../streaming/tags/EndsTag.kt | 2 - .../streaming/tags/ParticipantTag.kt | 6 - .../streaming/tags/PinnedEventTag.kt | 2 - .../streaming/tags/RecordingTag.kt | 2 - .../streaming/tags/RelayListTag.kt | 2 - .../streaming/tags/StartsTag.kt | 2 - .../streaming/tags/StatusTag.kt | 3 - .../streaming/tags/StreamingTag.kt | 2 - .../streaming/tags/TotalParticipantsTag.kt | 2 - .../quartz/nip54Wiki/WikiNoteEvent.kt | 7 +- .../quartz/nip56Reports/ReportEvent.kt | 3 +- .../quartz/nip56Reports/ReportType.kt | 2 +- .../quartz/nip56Reports/TagArrayBuilderExt.kt | 2 +- .../quartz/nip56Reports/tags/BaseReportTag.kt | 0 .../nip56Reports/tags/DefaultReportTag.kt | 2 - .../quartz/nip56Reports/tags/HashSha256Tag.kt | 2 - .../nip56Reports/tags/ReportedAddressTag.kt | 4 +- .../nip56Reports/tags/ReportedAuthorTag.kt | 2 - .../nip56Reports/tags/ReportedEventTag.kt | 2 - .../quartz/nip56Reports/tags/ServerTag.kt | 3 - .../quartz/nip57Zaps/LnZapEvent.kt | 8 +- .../quartz/nip57Zaps/LnZapEventInterface.kt | 2 +- .../quartz/nip57Zaps/LnZapPrivateEvent.kt | 2 +- .../quartz/nip57Zaps/LnZapRequestEvent.kt | 2 +- .../quartz/nip57Zaps/PrivateZapCache.kt | 0 .../quartz/nip57Zaps/PrivateZapEncryption.kt | 42 +- .../nip57Zaps/PrivateZapRequestBuilder.kt | 0 .../nip57Zaps/splits/BaseZapSplitSetup.kt | 0 .../quartz/nip57Zaps/splits/EventExt.kt | 0 .../nip57Zaps/splits/TagArrayBuilderExt.kt | 0 .../quartz/nip57Zaps/splits/TagArrayExt.kt | 0 .../quartz/nip57Zaps/splits/ZapSplitSetup.kt | 0 .../splits/ZapSplitSetupLnAddress.kt | 0 .../nip57Zaps/splits/ZapSplitSetupParser.kt | 2 - .../splits/ZapSplitSetupSerializer.kt | 1 - .../quartz/nip57Zaps/zapraiser/EventExt.kt | 0 .../nip57Zaps/zapraiser/TagArrayBuilderExt.kt | 0 .../quartz/nip57Zaps/zapraiser/TagArrayExt.kt | 0 .../nip57Zaps/zapraiser/ZapRaiserTag.kt | 2 - .../quartz/nip58Badges/BadgeAwardEvent.kt | 4 +- .../nip58Badges/BadgeDefinitionEvent.kt | 0 .../quartz/nip58Badges/BadgeProfilesEvent.kt | 6 +- .../quartz/nip59Giftwrap/HostStub.kt | 0 .../quartz/nip59Giftwrap/WrappedEvent.kt | 5 +- .../quartz/nip59Giftwrap/rumors/Rumor.kt | 16 +- .../nip59Giftwrap/rumors/RumorAssembler.kt | 2 +- .../nip59Giftwrap/seals/SealedRumorEvent.kt | 6 +- .../nip59Giftwrap/wraps/GiftWrapEvent.kt | 6 +- .../RequestToVanishEvent.kt | 0 .../nip62RequestToVanish/tags/RelayTag.kt | 5 - .../tags/TagArrayBuilderExt.kt | 0 .../nip62RequestToVanish/tags/TagArrayExt.kt | 0 .../AdvertisedRelayListEvent.kt | 4 +- .../RelayListRecommendationProcessor.kt | 0 .../tags/AdvertisedRelayInfoTag.kt | 7 - .../quartz/nip68Picture/IMetaTagBuilderExt.kt | 0 .../quartz/nip68Picture/IMetaTagExt.kt | 0 .../quartz/nip68Picture/PictureEvent.kt | 4 +- .../quartz/nip68Picture/PictureMeta.kt | 0 .../quartz/nip68Picture/TagArrayBuilderExt.kt | 0 .../quartz/nip68Picture/tags/LocationTag.kt | 2 - .../nip68Picture/tags/UserAnnotationTag.kt | 2 - .../quartz/nip70ProtectedEvts/EventExt.kt | 0 .../nip70ProtectedEvts/TagArrayBuilderExt.kt | 0 .../quartz/nip70ProtectedEvts/TagArrayExt.kt | 0 .../nip70ProtectedEvts/tags/ProtectedTag.kt | 3 - .../quartz/nip71Video/IMetaTagBuilderExt.kt | 0 .../quartz/nip71Video/IMetaTagExt.kt | 0 .../quartz/nip71Video/RegularVideoEvent.kt | 4 +- .../nip71Video/ReplaceableVideoEvent.kt | 4 +- .../quartz/nip71Video/TagArrayBuilderExt.kt | 0 .../quartz/nip71Video/VideoEvent.kt | 0 .../quartz/nip71Video/VideoHorizontalEvent.kt | 13 +- .../quartz/nip71Video/VideoMeta.kt | 0 .../quartz/nip71Video/VideoNormalEvent.kt | 0 .../quartz/nip71Video/VideoShortEvent.kt | 0 .../quartz/nip71Video/VideoVerticalEvent.kt | 10 +- .../quartz/nip71Video/tags/DurationTag.kt | 2 - .../quartz/nip71Video/tags/SegmentTag.kt | 2 - .../quartz/nip71Video/tags/TextTrackTag.kt | 2 - .../quartz/nip72ModCommunities/EventExt.kt | 2 +- .../approval/CommunityPostApprovalEvent.kt | 4 +- .../approval/TagArrayBuilderExt.kt | 2 + .../approval/tags/ApprovedAddressTag.kt | 14 +- .../approval/tags/ApprovedEventTag.kt | 9 - .../definition/CommunityDefinitionEvent.kt | 10 +- .../definition/TagArrayBuilderExt.kt | 0 .../definition/tags/DescriptionTag.kt | 2 - .../definition/tags/ImageTag.kt | 2 - .../definition/tags/ModeratorTag.kt | 4 - .../definition/tags/NameTag.kt | 2 - .../definition/tags/RelayTag.kt | 3 - .../definition/tags/RulesTag.kt | 2 - .../follow/CommunityListEvent.kt | 2 +- .../follow/TagArrayBuilderExt.kt | 4 +- .../nip72ModCommunities/follow/TagArrayExt.kt | 0 .../follow/tags/CommunityTag.kt | 15 +- .../nip73ExternalIds/CommentEventExt.kt | 0 .../quartz/nip73ExternalIds/ExternalId.kt | 0 .../quartz/nip73ExternalIds/books/BookId.kt | 0 .../nip73ExternalIds/books/CommentEventExt.kt | 0 .../location/CommentEventExt.kt | 0 .../nip73ExternalIds/location/GeohashId.kt | 0 .../movies/CommentEventExt.kt | 0 .../quartz/nip73ExternalIds/movies/MovieId.kt | 0 .../papers/CommentEventExt.kt | 0 .../quartz/nip73ExternalIds/papers/PaperId.kt | 0 .../podcasts/CommentEventExt.kt | 0 .../podcasts/PodcastEpisodeId.kt | 0 .../podcasts/PodcastFeedId.kt | 0 .../podcasts/PodcastPublisherId.kt | 0 .../topics/CommentEventExt.kt | 0 .../nip73ExternalIds/topics/HashtagId.kt | 0 .../nip73ExternalIds/urls/CommentEventExt.kt | 0 .../quartz/nip73ExternalIds/urls/UrlId.kt | 5 +- .../quartz/nip75ZapGoals/GoalEvent.kt | 4 +- .../nip75ZapGoals/TagArrayBuilderExt.kt | 2 +- .../quartz/nip75ZapGoals/tags/AmountTag.kt | 2 - .../quartz/nip75ZapGoals/tags/ClosedAtTag.kt | 2 - .../quartz/nip75ZapGoals/tags/RelayListTag.kt | 3 - .../nip78AppData/AppSpecificDataEvent.kt | 4 +- .../quartz/nip84Highlights/HighlightEvent.kt | 6 +- .../quartz/nip84Highlights/tags/CommentTag.kt | 2 - .../quartz/nip84Highlights/tags/ContextTag.kt | 2 - .../quartz/nip89AppHandlers/PlatformType.kt | 0 .../nip89AppHandlers/clientTag/ClientTag.kt | 7 +- .../nip89AppHandlers/clientTag/EventExt.kt | 0 .../clientTag/TagArrayBuilderExt.kt | 0 .../nip89AppHandlers/clientTag/TagArrayExt.kt | 0 .../definition/AppDefinitionEvent.kt | 16 +- .../definition/AppMetadata.kt | 13 +- .../nip89AppHandlers/definition/EntityType.kt | 0 .../definition/TagArrayBuilderExt.kt | 0 .../definition/tags/PlatformLinkTag.kt | 3 - .../recommendation/AppRecommendationEvent.kt | 2 +- .../recommendation/TagArrayBuilderExt.kt | 2 +- .../recommendation/tags/RecommendationTag.kt | 10 +- .../NIP90ContentDiscoveryRequestEvent.kt | 0 .../NIP90ContentDiscoveryResponseEvent.kt | 12 +- .../quartz/nip90Dvms/NIP90StatusEvent.kt | 0 .../NIP90UserDiscoveryRequestEvent.kt | 0 .../NIP90UserDiscoveryResponseEvent.kt | 0 .../quartz/nip92IMeta/EventExt.kt | 0 .../quartz/nip92IMeta/IMetaTag.kt | 0 .../quartz/nip92IMeta/IMetaTagBuilder.kt | 0 .../quartz/nip92IMeta/TagArrayBuilderExt.kt | 0 .../quartz/nip92IMeta/TagArrayExt.kt | 0 .../nip94FileMetadata/FileHeaderEvent.kt | 0 .../nip94FileMetadata/IMetaTagBuilderExt.kt | 0 .../nip94FileMetadata/TagArrayBuilderExt.kt | 0 .../nip94FileMetadata/tags/BlurhashTag.kt | 2 - .../nip94FileMetadata/tags/DimensionTag.kt | 5 +- .../nip94FileMetadata/tags/FallbackTag.kt | 2 - .../nip94FileMetadata/tags/HashSha256Tag.kt | 2 - .../quartz/nip94FileMetadata/tags/ImageTag.kt | 2 - .../nip94FileMetadata/tags/MagnetTag.kt | 2 - .../nip94FileMetadata/tags/MimeTypeTag.kt | 2 - .../nip94FileMetadata/tags/OriginalHashTag.kt | 2 - .../nip94FileMetadata/tags/ServiceTag.kt | 3 - .../quartz/nip94FileMetadata/tags/SizeTag.kt | 2 - .../nip94FileMetadata/tags/SummaryTag.kt | 3 - .../quartz/nip94FileMetadata/tags/ThumbTag.kt | 2 - .../nip94FileMetadata/tags/TorrentInfoHash.kt | 2 - .../quartz/nip94FileMetadata/tags/UrlTag.kt | 3 - .../nip96FileStorage/actions/DeleteResult.kt | 13 +- .../nip96FileStorage/actions/UploadResult.kt | 20 +- .../config/FileServersEvent.kt | 4 +- .../config/TagArrayBuilderExt.kt | 0 .../nip96FileStorage/config/tags/ServerTag.kt | 3 - .../nip96FileStorage/info/ServerInfo.kt | 31 +- .../nip96FileStorage/info/ServerInfoParser.kt | 29 +- .../nip98HttpAuth/HTTPAuthorizationEvent.kt | 4 +- .../nip98HttpAuth/TagArrayBuilderExt.kt | 0 .../quartz/nip98HttpAuth/tags/MethodTag.kt | 2 - .../nip98HttpAuth/tags/PayloadHashTag.kt | 3 - .../quartz/nip98HttpAuth/tags/UrlTag.kt | 2 - .../nip99Classifieds/ClassifiedsEvent.kt | 12 +- .../nip99Classifieds/ProductImageMeta.kt | 0 .../nip99Classifieds/TagArrayBuilderExt.kt | 0 .../nip99Classifieds/tags/ConditionTag.kt | 3 - .../nip99Classifieds/tags/LocationTag.kt | 2 - .../quartz/nip99Classifieds/tags/PriceTag.kt | 2 - .../quartz/nip99Classifieds/tags/StatusTag.kt | 2 - .../quartz/nipA0VoiceMessages/AudioMeta.kt | 0 .../nipA0VoiceMessages/BaseVoiceEvent.kt | 0 .../nipA0VoiceMessages/IMetaTagBuilderExt.kt | 0 .../quartz/nipA0VoiceMessages/IMetaTagExt.kt | 0 .../nipA0VoiceMessages/TagArrayBuilderExt.kt | 0 .../quartz/nipA0VoiceMessages/VoiceEvent.kt | 0 .../nipA0VoiceMessages/VoiceReplyEvent.kt | 0 .../nipA0VoiceMessages/tags/DurationTag.kt | 2 - .../nipA0VoiceMessages/tags/HashSha256Tag.kt | 2 - .../nipA0VoiceMessages/tags/MimeTypeTag.kt | 2 - .../nipA0VoiceMessages/tags/ReplyAuthorTag.kt | 5 - .../nipA0VoiceMessages/tags/ReplyEventTag.kt | 9 - .../nipA0VoiceMessages/tags/ReplyKindTag.kt | 10 - .../nipA0VoiceMessages/tags/WaveformTag.kt | 6 - .../nipB7Blossom/BlossomAuthorizationEvent.kt | 0 .../nipB7Blossom/BlossomServersEvent.kt | 4 +- .../nipB7Blossom/BlossomUploadResult.kt | 44 + .../vitorpamplona/quartz/utils/ArrayUtils.kt | 0 .../vitorpamplona/quartz/utils/BigDecimal.kt | 40 + .../com/vitorpamplona/quartz/utils/BitSet.kt} | 22 +- .../quartz/utils/ByteArrayOutputStream.kt | 92 + .../com/vitorpamplona/quartz/utils/Ensure.kt | 0 .../quartz/utils}/EventFactory.kt | 2 +- .../com/vitorpamplona/quartz/utils/GZip.kt | 27 + .../com/vitorpamplona/quartz/utils/Hex.kt | 7 +- .../vitorpamplona/quartz/utils/IterableExt.kt | 0 .../quartz/utils/JsonElementExt.kt | 27 + .../quartz/utils/LibSodiumInstance.kt | 54 + .../com/vitorpamplona/quartz/utils/Log.kt | 45 + .../quartz/utils/MapOfSetBuilder.kt | 0 .../quartz/utils/ParallelUtils.kt | 0 .../quartz/{ => utils}/Platform.kt | 4 +- .../quartz/utils/RandomInstance.kt | 6 +- .../com/vitorpamplona/quartz/utils/Rfc3986.kt | 31 + .../quartz/utils/Secp256k1Instance.kt | 54 + .../quartz/utils/SecureRandom.kt | 27 + .../vitorpamplona/quartz/utils/StringExt.kt} | 4 +- .../vitorpamplona/quartz/utils/StringUtils.kt | 0 .../vitorpamplona/quartz/utils/TimeUtils.kt | 2 +- .../quartz/utils/UnicodeNormalizer.kt | 32 + .../vitorpamplona/quartz/utils/UriParser.kt | 39 + .../vitorpamplona/quartz/utils/UrlEncoder.kt | 27 + .../com/vitorpamplona/quartz/utils/Urls.kt | 23 + .../quartz/utils/cache/CacheCollectors.kt | 65 + .../quartz/utils/cache/ICacheOperations.kt | 81 + .../quartz/utils/cache/LargeCache.kt | 103 + .../quartz/utils/ciphers/AESCBC.kt | 39 + .../quartz/utils/ciphers/AESGCM.kt | 39 + .../quartz/utils/ciphers}/NostrCipher.kt | 2 +- .../quartz/utils/diggest/DigestInstance.kt | 33 + .../quartz/utils/mac/MacInstance.kt | 44 + .../quartz/utils/sha256/Sha256.kt | 23 + .../quartz/RandomInstanceTest.kt | 50 + .../quartz/TestResourceLoader.kt} | 15 +- .../quartz/lightning/Lud06Test.kt | 4 +- .../nip01Core/hints/BloomFilterMurMur3Test.kt | 37 +- .../quartz/nip01Core/hints/HintIndexerTest.kt | 107 +- .../quartz/nip01Core/hints/MurMur3Test.kt | 4 +- .../jackson/EventDeserializerTest.kt | 22 +- .../InliningTagArrayPrettyPrinterTest.kt | 2 +- .../nip01Core/metadata/UpdateMetadataTest.kt | 7 +- .../nip01Core/relay/RelayUrlFormatterTest.kt | 4 +- .../quartz/nip05DnsIdentifiers/Nip05Test.kt | 8 +- .../quartz/nip19Bech32/NIP19ParserTest.kt | 55 +- .../quartz/nip19Bech32/TlvIntegerTest.kt | 2 +- .../quartz/nip30CustomEmoji/Nip30Test.kt | 8 +- .../quartz/nip44Encryption/crypto/HkdfText.kt | 14 +- .../nip46RemoteSigner/BunkerRequestTest.kt | 11 +- .../quartz/nip51Lists/TagArrayExt.kt | 12 +- .../RelayListRecommendationProcessorTest.kt | 6 +- .../quartz/nip96FileStorage/Nip96Test.kt | 6 +- .../quartz/utils/HexEncodingTest.kt | 32 +- .../vitorpamplona/quartz/utils/SignerUtils.kt | 0 .../quartz/utils/StringUtilsTest.kt | 12 +- .../quartz/nip01Core/core/Address.ios.kt | 67 + .../nip01Core/core/OptimizedJsonMapper.ios.kt | 35 + .../crypto/EventHasherSerializer.ios.kt | 45 + .../info/ServerInfoParser.ios.kt | 28 + .../vitorpamplona/quartz/utils/BigDecimal.kt | 73 + .../vitorpamplona/quartz/utils/BitSet.ios.kt | 51 + .../vitorpamplona/quartz/utils/GZip.ios.kt} | 14 +- .../quartz/utils/LibSodiumInstance.ios.kt | 61 + .../com/vitorpamplona/quartz/utils/Log.ios.kt | 63 + .../quartz/utils/Platform.ios.kt | 33 + .../vitorpamplona/quartz/utils/Rfc3986.ios.kt | 31 + .../quartz/utils/Secp256k1Instance.ios.kt | 68 + .../quartz/utils/SecureRandom.ios.kt | 73 + .../quartz/utils/StringExt.ios.kt | 23 + .../vitorpamplona/quartz/utils/URLs.ios.kt | 25 + .../quartz/utils/UnicodeNormalizer.ios.kt | 27 + .../quartz/utils/UriParser.ios.kt | 67 + .../quartz/utils/UrlEncoder.ios.kt | 31 + .../quartz/utils/cache/LargeCache.ios.kt | 160 ++ .../quartz/utils/ciphers/AESCBC.ios.kt | 42 + .../quartz/utils/ciphers/AESGCM.ios.kt | 42 + .../utils/diggest/DigestInstance.ios.kt | 41 + .../quartz/utils/mac/MacInstance.kt | 56 + .../quartz/utils/sha256/Sha256.kt | 45 + .../quartz/TestResourceLoader.kt | 45 + quartz/src/iosTest/resources/relayDB.txt | 2539 +++++++++++++++++ .../core/OptimizedJsonMapper.jvmAndroid.kt | 45 + .../EventHasherSerializer.jvmAndroid.kt | 114 + .../nip01Core/jackson/EventDeserializer.kt | 0 .../jackson/EventManualDeserializer.kt | 2 +- .../jackson/EventManualSerializer.kt | 2 +- .../nip01Core/jackson/EventSerializer.kt | 0 .../jackson/InliningTagArrayPrettyPrinter.kt | 0 .../quartz/nip01Core/jackson/JacksonExt.kt | 0 .../quartz/nip01Core/jackson/JacksonMapper.kt | 122 + .../nip01Core/jackson/TagArrayDeserializer.kt | 0 .../jackson/TagArrayManualDeserializer.kt | 0 .../nip01Core/jackson/TagArraySerializer.kt | 0 .../commands/toClient/MessageDeserializer.kt | 94 + .../commands/toClient/MessageSerializer.kt | 75 + .../commands/toRelay/CommandDeserializer.kt | 115 + .../commands/toRelay/CommandSerializer.kt | 73 + .../relay/filters/FilterDeserializer.kt | 12 +- .../relay/filters/FilterSerializer.kt | 76 + .../sockets/okhttp/BasicOkHttpWebSocket.kt | 20 +- .../signers/EventTemplateDeserializer.kt | 0 .../EventTemplateManualDeserializer.kt | 0 .../signers/EventTemplateSerializer.kt | 48 + .../okhttp/OkHttpBitcoinExplorer.kt | 34 +- .../nip03Timestamp/okhttp/OkHttpCalendar.kt | 115 + .../okhttp/OkHttpOtsResolverBuilder.kt | 19 +- .../jackson/BunkerMessageDeserializer.kt} | 32 +- .../jackson/BunkerRequestDeserializer.kt | 64 + .../jackson/BunkerRequestSerializer.kt} | 35 +- .../jackson/BunkerResponseDeserializer.kt | 79 + .../jackson/BunkerResponseSerializer.kt | 40 + .../jackson}/RequestDeserializer.kt | 4 +- .../jackson}/ResponseDeserializer.kt | 5 +- .../rumors/jackson}/RumorDeserializer.kt | 3 +- .../rumors/jackson}/RumorSerializer.kt | 3 +- .../info/ServerInfoParser.jvmAndroid.kt | 39 + .../vitorpamplona/quartz/utils/BigDecimal.kt | 25 + .../quartz/utils/BitSet.jvmAndroid.kt | 27 + .../quartz/utils/GZip.jvmAndroid.kt} | 16 +- .../quartz/utils/Rfc3986.jvmAndroid.kt} | 22 + .../quartz/utils/SecureRandom.jvmAndroid.kt | 25 + .../quartz/utils/StringExt.jvmAndroid.kt | 23 + .../quartz/utils/UnicodeNormalizer.kt | 27 + .../quartz/utils/UrlEncoder.jvmAndroid.kt | 30 + .../com/vitorpamplona/quartz/utils/Urls.kt | 26 + .../quartz/utils/cache}/CacheCollectors.kt | 56 +- .../quartz/utils/cache}/CacheOperations.kt | 67 +- .../utils/cache/LargeCache.jvmAndroid.kt} | 26 +- .../utils/ciphers/AESCBC.jvmAndroid.kt} | 20 +- .../utils/ciphers/AESGCM.jvmAndroid.kt} | 19 +- .../diggest/DigestInstance.jvmAndroid.kt | 37 + .../quartz/utils/mac}/FixedKey.kt | 27 +- .../utils/mac/MacInstance.jvmAndroid.kt | 51 + .../quartz/utils/sha256/Sha256.jvmAndroid.kt} | 2 +- .../utils/sha256/Sha256Hasher.jvmAndroid.kt} | 0 .../utils/sha256/Sha256Pool.jvmAndroid.kt} | 4 +- .../quartz/nip01Core/core/Address.jvm.kt | 67 + .../quartz/utils/LibSodiumInstance.jvm.kt | 104 + .../com/vitorpamplona/quartz/utils/Log.jvm.kt | 61 + .../quartz/{ => utils}/Platform.jvm.kt | 4 +- .../quartz/utils/Secp256k1Instance.jvm.kt | 59 + .../quartz/utils/UriParser.jvm.kt | 73 + .../quartz/TestResourceLoader.kt | 30 + quartz/src/jvmTest/resources/relayDB.txt | 2539 +++++++++++++++++ 1195 files changed, 12671 insertions(+), 5183 deletions(-) rename {quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils => amethyst/src/main/java/com/vitorpamplona/amethyst/model}/LargeSoftCache.kt (97%) create mode 100644 amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/TorAwareOkHttpOtsResolverBuilder.kt rename quartz/{src/androidInstrumentedTest/resources => }/relayDB.txt (100%) rename quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/{tags/addressables => core}/Address.kt (59%) delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasher.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JsonMapper.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CountCmd.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/ReqCmd.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/ToRelayParser.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterSerializer.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Utils.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/BlockstreamExplorer.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/Calendar.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/CalendarAsyncSubmit.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/Request.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/Response.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpCalendar.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpCalendarAsyncSubmit.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpCalendarBuilder.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequest.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponse.kt delete mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/SecretKeyOrEmptySpec.kt create mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/JsonMapperNip55.kt rename quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/{LibSodiumInstance.kt => LibSodiumInstance.android.kt} (93%) create mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Log.android.kt rename quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/{ => utils}/Platform.android.kt (91%) rename quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/{Secp256k1Instance.kt => Secp256k1Instance.android.kt} (82%) create mode 100644 quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.android.kt rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OtsBlockHeightCache.kt => androidUnitTest/kotlin/com/vitorpamplona/quartz/TestResourceLoader.kt} (79%) create mode 100644 quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexerMemoryTest.kt rename quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/{sqlite => sqllite}/EventDbQueryAssemblerTest.kt (99%) rename quartz/src/androidUnitTest/{kotlin/com/vitorpamplona/quartz/nip01Core/hints => resources}/relayDB.txt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/audio/header/AudioHeaderEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/audio/header/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/DownloadUrlTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/StreamUrlTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/WaveformTag.kt (86%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/audio/track/AudioTrackEvent.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/audio/track/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/CoverTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/MediaTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/ParticipantTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/PriceTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/TypeTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/bounties/BountyAddValueEvent.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/bounties/EventExt.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/bounties/RewardTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/bounties/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/decoupling/DecoupledCipher.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/decoupling/EncryptionKeyCache.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/decoupling/EncryptionKeyDerivation.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/EncryptionKeyListEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/tags/KeyTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/edits/TextNoteModificationEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/EphemeralChatEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/RoomId.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/tags/RelayTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/tags/RoomTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/db/EphemeralRoom.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/db/EphemeralRoomCache.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/EphemeralChatListEvent.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/tags/RoomIdTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/forks/BaseThreadedEventExt.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/forks/MarkedETagExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/inlineMetadata/Nip54InlineMetadata.kt (73%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryBaseEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryPrologueEvent.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStorySceneEvent.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/TagArrayBuilderExt.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/ReadStatusTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/RootSceneTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/StoryOptionTag.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/limits/LimitProcessor.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/limits/Limits.kt (50%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/medical/FhirResourceEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/nip95/data/FileStorageEvent.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/nip95/data/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/nip95/header/FileStorageHeaderEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/nip95/header/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/nns/NNSEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/nns/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/IPv4Tag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/IPv6Tag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/VersionTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/GalleryListEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/ProfileGalleryEntryEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/PublicMessageEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/tags/ReceiverTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/ContactCardEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/PetNameTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/RankTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/SummaryTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/PollNoteEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/ClosedAtTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/ConsensusThresholdTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/MaximumTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/MinimumTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/PollOptionTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/lightning/LnInvoiceUtil.kt (89%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/lightning/LnWithdrawalUtil.kt (86%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/lightning/Lud06.kt (82%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressSerializer.kt rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressableEvent.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt (90%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt (87%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/core/Event.kt (89%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/core/HexKey.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/core/IEvent.kt (100%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip02FollowList => commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core}/ImmutableListOfLists.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/core/Kind.kt (100%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/OptimizedJsonMapper.kt rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/core/Tag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/core/TagArrayBuilder.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/DeterministicSigner.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventAssembler.kt (97%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip01Core => commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto}/EventExt.kt (92%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasher.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasherSerializer.kt rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/KeyPair.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/Nip01.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/hints/EventHintBundle.kt (73%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexer.kt (87%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintProviders.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/BitSetExt.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/BloomFilterMurMur3.kt (76%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/MurmurHash3.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/AddressHint.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/EventIdHint.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/Hint.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/PubKeyHint.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/MetadataEvent.kt (57%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/UserMetadata.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/AboutTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/BannerTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/DisplayNameTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Lud06Tag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Lud16Tag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/NameTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Nip05Tag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/PictureTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/PronounsTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/WebsiteTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/INostrClient.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/NostrClient.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/NostrClientSubscription.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/EventCollector.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/NostrClientSendAndWaitExt.kt (55%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/NostrClientSingleDownloadExt.kt (82%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayAuthenticator.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayInsertConfirmationCollector.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayLogger.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayNotifier.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/listeners/IRelayClientListener.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/listeners/RedirectRelayClientListener.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutbox.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutboxRepository.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolSubscriptionRepository.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/RelayBasedFilter.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/RelayPool.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/IRelayClient.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/Subscription.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClient.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/simple/OutboxCache.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/simple/SimpleRelayClient.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/stats/RelayStat.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/stats/RelayStats.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/Subscription.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/SubscriptionController.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/SubscriptionStats.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/AuthMessage.kt (86%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/ClosedMessage.kt (82%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/EoseMessage.kt (86%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/EventMessage.kt (81%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/Message.kt (89%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/NoticeMessage.kt (89%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/NotifyMessage.kt (86%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/OkMessage.kt (82%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/AuthCmd.kt (77%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CloseCmd.kt (79%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/Command.kt (89%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CountCmd.kt rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/EventCmd.kt (78%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/ReqCmd.kt rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/Filter.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterMatcher.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/normalizer/NormalizedRelayUrl.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/normalizer/RelayUrlNormalizer.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebSocket.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebSocketListener.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebsocketBuilder.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebsocketBuilderFactory.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplate.kt (85%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSigner.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSignerInternal.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSignerSync.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/signers/SignerExceptions.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/signers/caches/CacheResults.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/signers/caches/DecryptCache.kt (91%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables => commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag}/ATag.kt (87%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables => commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag}/EventExt.kt (97%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables => commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag}/TagArrayBuilderExt.kt (83%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables => commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag}/TagArrayExt.kt (97%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags => commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag}/DTag.kt (94%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags => commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag}/EventExt.kt (95%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags => commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag}/TagArrayBuilderExt.kt (96%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags => commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag}/TagArrayExt.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/ETag.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/EventReference.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/GenericETag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayBuilderExt.kt (86%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeoHashTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeohashPrecision.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/HashtagTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/MipMapHashTags.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/KindTag.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/EntityExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/PTag.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/PubKeyReferenceTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/publishedAt/PublishedAtProvider.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/EventExt.kt (100%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage => commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references}/HttpUrlFormatter.kt (88%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/ReferenceTag.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip02FollowList/ContactListEvent.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip02FollowList/RelaySet.kt (86%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip02FollowList/tags/ContactTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsEvent.kt (87%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsResolver.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsResolverBuilder.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/VerificationState.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/VerificationStateCache.kt (88%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/BitcoinExplorer.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/BlockHeader.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/DetachedTimestampFile.kt (75%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Hash.kt (74%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Merkle.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OpenTimestamps.kt (74%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OtsBlockHeightCache.kt rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/README.md (100%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/RemoteCalendar.kt rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/StreamDeserializationContext.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/StreamSerializationContext.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Timestamp.kt (93%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/ICalendar.kt => commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Utils.kt} (60%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/VerifyResult.kt (76%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/BitcoinBlockHeaderAttestation.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/PendingAttestation.kt (84%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/TimeAttestation.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/UnknownAttestation.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Digest.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/ExtendedDigest.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/GeneralDigest.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/KeccakDigest.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Memoable.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Pack.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/RIPEMD160Digest.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/CommitmentNotFoundException.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/DeserializationException.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/ExceededSizeException.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/UrlException.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/VerificationException.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/Op.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpAppend.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpBinary.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpCrypto.kt (60%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpKECCAK256.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpPrepend.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpRIPEMD160.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpSHA1.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpSHA256.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpUnary.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/tags/TargetEventKindTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip03Timestamp/tags/TargetEventTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip04Dm/PrivateDMCache.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/EncryptedInfo.kt (87%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/Encryption.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/Nip04.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip04Dm/messages/PrivateDmEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip04Dm/messages/TagArrayBuilderExt.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/Nip05.kt (75%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip32SeedDerivation.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39KeyPath.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39Mnemonics.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Nip06.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionIndex.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip10Notes/BaseNoteEvent.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip10Notes/BaseThreadedEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip10Notes/TextNoteEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip10Notes/content/ContentHashTags.kt (86%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip10Notes/content/IndexedTags.kt (86%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip10Notes/content/NostrUris.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip10Notes/content/Urls.kt (82%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/MarkedETag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/Positional.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/ReplyBuilder.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip11RelayInfo/Nip11RelayInformation.kt (85%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip13Pow/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip13Pow/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip13Pow/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/ByteArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/MiningBuffer.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/PoWMiner.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/PoWRankEvaluator.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip13Pow/tags/PoWTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip14Subject/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip14Subject/SubjectTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip14Subject/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip14Subject/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/NIP17Factory.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/base/BaseDMGroupEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/base/ChatroomKey.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/base/ChatroomKeyable.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/base/NIP17Group.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/files/ChatMessageEncryptedFileHeaderEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/files/TagArrayBuilderExt.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionAlgo.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionKey.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionNonce.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/FileTypeTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/messages/ChatMessageEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/messages/TagArrayBuilderExt.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/settings/ChatMessageRelayListEvent.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip17Dm/settings/tags/RelayTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip18Reposts/GenericRepostEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip18Reposts/RepostEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/EntityExt.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QAddressableTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QEventTag.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/ATagExt.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/ByteArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/EventExt.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/ListEntityExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/Nip19Parser.kt (80%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvTypes.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/bech32/Bech32Util.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/Entity.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NAddress.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NEmbed.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NNote.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NProfile.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NPub.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NRelay.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NSec.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/tlv/Tlv.kt (77%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip19Bech32/tlv/TlvBuilder.kt (90%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip21UriScheme/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip22Comments/CommentEvent.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip22Comments/RootScope.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip22Comments/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyAddressTag.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyAuthorTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyEventTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyIdentifierTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyKindTag.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootAddressTag.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootAuthorTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootEventTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootIdentifierTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootKindTag.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip23LongContent/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/ImageTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/PublishedAtTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/SummaryTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/TitleTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip25Reactions/ReactionEvent.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelCreateEvent.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelHideMessageEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelMetadataEvent.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelMuteUserEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/BasePublicChatEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/ChannelData.kt (86%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/IsInPublicChatChannel.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/TagArrayBuilderExt.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/ChannelListEvent.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/tags/ChannelTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip28PublicChat/message/ChannelMessageEvent.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/CustomEmoji.kt (83%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/EmojiUrlTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/pack/EmojiPackEvent.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/EmojiPackSelectionEvent.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/TagArrayBuilderExt.kt (84%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip31Alts/AltTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip31Alts/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip31Alts/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip31Alts/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip34Git/issue/GitIssueEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip34Git/issue/TagArrayBuilderExt.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip34Git/patch/GitPatchEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip34Git/reply/GitReplyEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip34Git/reply/TagArrayBuilderExt.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip34Git/repository/GitRepositoryEvent.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip34Git/repository/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/CloneTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/DescriptionTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/NameTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/WebTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip35Torrents/DefaultTrackers.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip35Torrents/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip35Torrents/TorrentCommentEvent.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip35Torrents/TorrentEvent.kt (85%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/BtihTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/FileTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/InfoHashTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/TrackerTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/ContentWarningTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip37Drafts/DraftWrapCache.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip37Drafts/DraftWrapEvent.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip37Drafts/ExposeInDraft.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip37Drafts/privateOutbox/PrivateOutboxRelayListEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip38UserStatus/StatusEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/GitHubIdentity.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/IdentityClaimTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/MastodonIdentity.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TelegramIdentity.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TwitterIdentity.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/UnsupportedIdentity.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip40Expiration/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip40Expiration/ExpirationTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip40Expiration/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip40Expiration/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/RelayAuthEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/tags/ChallengeTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/tags/RelayTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip44Encryption/EncryptedInfoString.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44.kt (82%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v1.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v2.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip44Encryption/SharedKeyCache.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/ChaCha20.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/Hkdf.kt (88%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/CalendarBuilder.kt => commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerMessage.kt} (82%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequest.kt rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestConnect.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestGetPublicKey.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestGetRelays.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip04Decrypt.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip04Encrypt.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip44Decrypt.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip44Encrypt.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestPing.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestSign.kt (92%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponse.kt rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseAck.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseDecrypt.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseEncrypt.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseError.kt (84%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseEvent.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseGetRelays.kt (72%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponsePong.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponsePublicKey.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/NostrConnectEvent.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/LnZapPaymentRequestEvent.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/LnZapPaymentResponseEvent.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Nip47WalletConnect.kt (85%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/NostrWalletConnectRequestCache.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/NostrWalletConnectResponseCache.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Request.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Response.kt (84%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/ProxyTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/ByteArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49.kt (89%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/PBKDF.kt (81%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/SCrypt.kt (85%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip50Search/SearchRelayListEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip50Search/SearchableEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/PinListEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayBuilder.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayEventCache.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/BookmarkListEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/AddressBookmark.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/BookmarkIdTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/EventBookmark.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/encryption/NostrSignerExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/encryption/PrivateTagsInContent.kt (87%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/FollowListEvent.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/GeohashListEvent.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/HashtagListEvent.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/MuteListEvent.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/MuteTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/UserTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/WordTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/PeopleListEvent.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/BlockedRelayListEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/BroadcastRelayListEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/IndexerRelayListEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/ProxyRelayListEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/TrustedRelayListEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/RelayTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/relaySets/RelaySetEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/DescriptionTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/ImageTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/NameTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/RelayTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/TitleTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarDateSlotEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarRSVPEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarTimeSlotEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/chat/LiveActivitiesChatMessageEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/chat/TagArrayBuilderExt.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/MeetingRoomEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/MeetingSpaceEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/EndpointUrlTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/MeetingSpaceTag.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RecordingTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RelayListTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RoomNameTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/ServiceUrlTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/StatusTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/MeetingRoomPresenceEvent.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/TagArrayBuilderExt.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/tags/HandRaisedTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/tags/MeetingRoomTag.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/LiveActivitiesEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/CurrentParticipantsTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/EndsTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/ParticipantTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/PinnedEventTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/RecordingTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/RelayListTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StartsTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StatusTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StreamingTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/TotalParticipantsTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip56Reports/ReportEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip56Reports/ReportType.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip56Reports/TagArrayBuilderExt.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/BaseReportTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/DefaultReportTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/HashSha256Tag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedAddressTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedAuthorTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedEventTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ServerTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapEvent.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapEventInterface.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapPrivateEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapCache.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapEncryption.kt (71%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapRequestBuilder.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/BaseZapSplitSetup.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetup.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupLnAddress.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupParser.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupSerializer.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/ZapRaiserTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeAwardEvent.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeDefinitionEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeProfilesEvent.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/HostStub.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/WrappedEvent.kt (90%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/Rumor.kt (83%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/RumorAssembler.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/seals/SealedRumorEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/wraps/GiftWrapEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/RequestToVanishEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/RelayTag.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip65RelayList/AdvertisedRelayListEvent.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip65RelayList/RelayListRecommendationProcessor.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip65RelayList/tags/AdvertisedRelayInfoTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip68Picture/IMetaTagBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip68Picture/IMetaTagExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip68Picture/PictureEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip68Picture/PictureMeta.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip68Picture/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip68Picture/tags/LocationTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip68Picture/tags/UserAnnotationTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/tags/ProtectedTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip71Video/IMetaTagBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip71Video/IMetaTagExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip71Video/RegularVideoEvent.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip71Video/ReplaceableVideoEvent.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip71Video/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip71Video/VideoEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip71Video/VideoHorizontalEvent.kt (90%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip71Video/VideoMeta.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip71Video/VideoNormalEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip71Video/VideoShortEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip71Video/VideoVerticalEvent.kt (90%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip71Video/tags/DurationTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip71Video/tags/SegmentTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip71Video/tags/TextTrackTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/EventExt.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/CommunityPostApprovalEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/TagArrayBuilderExt.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/tags/ApprovedAddressTag.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/tags/ApprovedEventTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/CommunityDefinitionEvent.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/DescriptionTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/ImageTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/ModeratorTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/NameTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/RelayTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/RulesTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/CommunityListEvent.kt (99%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/TagArrayBuilderExt.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/tags/CommunityTag.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/CommentEventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/ExternalId.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/books/BookId.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/books/CommentEventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/location/CommentEventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/location/GeohashId.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/movies/CommentEventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/movies/MovieId.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/papers/CommentEventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/papers/PaperId.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/CommentEventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastEpisodeId.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastFeedId.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastPublisherId.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/topics/CommentEventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/topics/HashtagId.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/urls/CommentEventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/urls/UrlId.kt (92%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/GoalEvent.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/TagArrayBuilderExt.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/AmountTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/ClosedAtTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/RelayListTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip78AppData/AppSpecificDataEvent.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip84Highlights/HighlightEvent.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip84Highlights/tags/CommentTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip84Highlights/tags/ContextTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/PlatformType.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/ClientTag.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppDefinitionEvent.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppMetadata.kt (91%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/EntityType.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/tags/PlatformLinkTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/AppRecommendationEvent.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/TagArrayBuilderExt.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/tags/RecommendationTag.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90ContentDiscoveryRequestEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90ContentDiscoveryResponseEvent.kt (90%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90StatusEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90UserDiscoveryRequestEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90UserDiscoveryResponseEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip92IMeta/EventExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip92IMeta/IMetaTag.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip92IMeta/IMetaTagBuilder.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip92IMeta/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip92IMeta/TagArrayExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/FileHeaderEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/IMetaTagBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/BlurhashTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/DimensionTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/FallbackTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/HashSha256Tag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ImageTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/MagnetTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/MimeTypeTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/OriginalHashTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ServiceTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/SizeTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/SummaryTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ThumbTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/TorrentInfoHash.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/UrlTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip96FileStorage/actions/DeleteResult.kt (75%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip96FileStorage/actions/UploadResult.kt (69%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/FileServersEvent.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/tags/ServerTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfo.kt (54%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.kt (71%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/HTTPAuthorizationEvent.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/MethodTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/PayloadHashTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/UrlTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip99Classifieds/ClassifiedsEvent.kt (94%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip99Classifieds/ProductImageMeta.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip99Classifieds/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/ConditionTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/LocationTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/PriceTag.kt (98%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/StatusTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/AudioMeta.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/BaseVoiceEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/IMetaTagBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/IMetaTagExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/TagArrayBuilderExt.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/VoiceEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/VoiceReplyEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/DurationTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/HashSha256Tag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/MimeTypeTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyAuthorTag.kt (97%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyEventTag.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyKindTag.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/WaveformTag.kt (95%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomAuthorizationEvent.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomServersEvent.kt (96%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomUploadResult.kt rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/utils/ArrayUtils.kt (100%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimal.kt rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/utils/Hmac512.kt => commonMain/kotlin/com/vitorpamplona/quartz/utils/BitSet.kt} (82%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ByteArrayOutputStream.kt rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/utils/Ensure.kt (100%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz => commonMain/kotlin/com/vitorpamplona/quartz/utils}/EventFactory.kt (99%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/GZip.kt rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/utils/Hex.kt (96%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/utils/IterableExt.kt (100%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/JsonElementExt.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Log.kt rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/utils/MapOfSetBuilder.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/utils/ParallelUtils.kt (100%) rename quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/{ => utils}/Platform.kt (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/utils/RandomInstance.kt (90%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Rfc3986.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.kt rename quartz/src/{iosMain/kotlin/com/vitorpamplona/quartz/Platform.ios.kt => commonMain/kotlin/com/vitorpamplona/quartz/utils/StringExt.kt} (93%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/utils/StringUtils.kt (100%) rename quartz/src/{androidMain => commonMain}/kotlin/com/vitorpamplona/quartz/utils/TimeUtils.kt (97%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/UnicodeNormalizer.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/UrlEncoder.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Urls.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/CacheCollectors.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/ICacheOperations.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESCBC.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.kt rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/encryption => commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers}/NostrCipher.kt (95%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/diggest/DigestInstance.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/mac/MacInstance.kt create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.kt create mode 100644 quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/RandomInstanceTest.kt rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/CalendarPureJavaBuilder.kt => commonTest/kotlin/com/vitorpamplona/quartz/TestResourceLoader.kt} (80%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/lightning/Lud06Test.kt (96%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip01Core/hints/BloomFilterMurMur3Test.kt (85%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexerTest.kt (57%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip01Core/hints/MurMur3Test.kt (98%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializerTest.kt (81%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/InliningTagArrayPrettyPrinterTest.kt (99%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/UpdateMetadataTest.kt (97%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/RelayUrlFormatterTest.kt (97%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/Nip05Test.kt (96%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip19Bech32/NIP19ParserTest.kt (91%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvIntegerTest.kt (99%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/Nip30Test.kt (97%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/HkdfText.kt (96%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestTest.kt (80%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip51Lists/TagArrayExt.kt (85%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip65RelayList/RelayListRecommendationProcessorTest.kt (97%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/nip96FileStorage/Nip96Test.kt (98%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/utils/HexEncodingTest.kt (76%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/utils/SignerUtils.kt (100%) rename quartz/src/{androidUnitTest => commonTest}/kotlin/com/vitorpamplona/quartz/utils/StringUtilsTest.kt (93%) create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/OptimizedJsonMapper.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasherSerializer.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimal.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/BitSet.ios.kt rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/ICalendarAsyncSubmit.kt => iosMain/kotlin/com/vitorpamplona/quartz/utils/GZip.ios.kt} (81%) create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Log.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Platform.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Rfc3986.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/StringExt.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/URLs.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/UnicodeNormalizer.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/UrlEncoder.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESCBC.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/diggest/DigestInstance.ios.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/mac/MacInstance.kt create mode 100644 quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.kt create mode 100644 quartz/src/iosTest/kotlin/com/vitorpamplona/quartz/TestResourceLoader.kt create mode 100644 quartz/src/iosTest/resources/relayDB.txt create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/core/OptimizedJsonMapper.jvmAndroid.kt create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasherSerializer.jvmAndroid.kt rename quartz/src/{androidMain => jvmAndroid}/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializer.kt (100%) rename quartz/src/{androidMain => jvmAndroid}/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventManualDeserializer.kt (97%) rename quartz/src/{androidMain => jvmAndroid}/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventManualSerializer.kt (97%) rename quartz/src/{androidMain => jvmAndroid}/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventSerializer.kt (100%) rename quartz/src/{androidMain => jvmAndroid}/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/InliningTagArrayPrettyPrinter.kt (100%) rename quartz/src/{androidMain => jvmAndroid}/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonExt.kt (100%) create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapper.kt rename quartz/src/{androidMain => jvmAndroid}/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArrayDeserializer.kt (100%) rename quartz/src/{androidMain => jvmAndroid}/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArrayManualDeserializer.kt (100%) rename quartz/src/{androidMain => jvmAndroid}/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArraySerializer.kt (100%) create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/MessageDeserializer.kt create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/MessageSerializer.kt create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CommandDeserializer.kt create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CommandSerializer.kt rename quartz/src/{androidMain => jvmAndroid}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt (82%) create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterSerializer.kt rename quartz/src/{androidMain => jvmAndroid}/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/okhttp/BasicOkHttpWebSocket.kt (85%) rename quartz/src/{androidMain => jvmAndroid}/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplateDeserializer.kt (100%) rename quartz/src/{androidMain => jvmAndroid}/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplateManualDeserializer.kt (100%) create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplateSerializer.kt rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots => jvmAndroid/kotlin/com/vitorpamplona/quartz/nip03Timestamp}/okhttp/OkHttpBitcoinExplorer.kt (79%) create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip03Timestamp/okhttp/OkHttpCalendar.kt rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots => jvmAndroid/kotlin/com/vitorpamplona/quartz/nip03Timestamp}/okhttp/OkHttpOtsResolverBuilder.kt (76%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerMessage.kt => jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerMessageDeserializer.kt} (63%) create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerRequestDeserializer.kt rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/ToClientParser.kt => jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerRequestSerializer.kt} (57%) create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerResponseDeserializer.kt create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerResponseSerializer.kt rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect => jvmAndroid/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/jackson}/RequestDeserializer.kt (90%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect => jvmAndroid/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/jackson}/ResponseDeserializer.kt (90%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors => jvmAndroid/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/jackson}/RumorDeserializer.kt (94%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors => jvmAndroid/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/jackson}/RumorSerializer.kt (94%) create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.jvmAndroid.kt create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/BigDecimal.kt create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/BitSet.jvmAndroid.kt rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/utils/GZip.kt => jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/GZip.jvmAndroid.kt} (75%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/utils/UriReferenceExt.kt => jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/Rfc3986.jvmAndroid.kt} (75%) create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.jvmAndroid.kt create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/StringExt.jvmAndroid.kt create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/UnicodeNormalizer.kt create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/UrlEncoder.jvmAndroid.kt create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/Urls.kt rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/utils => jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache}/CacheCollectors.kt (87%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/utils => jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache}/CacheOperations.kt (67%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/utils/LargeCache.kt => jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.jvmAndroid.kt} (78%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/AESCBC.kt => jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESCBC.jvmAndroid.kt} (78%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/encryption/AESGCM.kt => jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.jvmAndroid.kt} (81%) create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/diggest/DigestInstance.jvmAndroid.kt rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto => jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/mac}/FixedKey.kt (65%) create mode 100644 quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/mac/MacInstance.jvmAndroid.kt rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.kt => jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.jvmAndroid.kt} (95%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256Hasher.kt => jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256Hasher.jvmAndroid.kt} (100%) rename quartz/src/{androidMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256Pool.kt => jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256Pool.jvmAndroid.kt} (96%) create mode 100644 quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.jvm.kt create mode 100644 quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.jvm.kt create mode 100644 quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/Log.jvm.kt rename quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/{ => utils}/Platform.jvm.kt (91%) create mode 100644 quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.jvm.kt create mode 100644 quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.jvm.kt create mode 100644 quartz/src/jvmTest/java/com/vitorpamplona/quartz/TestResourceLoader.kt create mode 100644 quartz/src/jvmTest/resources/relayDB.txt diff --git a/amethyst/build.gradle b/amethyst/build.gradle index d4f428a75b..34e20e5566 100644 --- a/amethyst/build.gradle +++ b/amethyst/build.gradle @@ -339,6 +339,9 @@ dependencies { // Cbor for cashuB format implementation libs.kotlinx.serialization.cbor + // Kotlin serialization for the times where we need the Json tree and performance is not that important. + implementation(libs.kotlinx.serialization.json) + implementation libs.tor.android implementation libs.jtorctl diff --git a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/CashuBTest.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/CashuBTest.kt index 8b8627eb5a..6e25285f05 100644 --- a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/CashuBTest.kt +++ b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/CashuBTest.kt @@ -24,9 +24,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.amethyst.service.cashu.CashuParser import com.vitorpamplona.amethyst.service.cashu.CashuToken import com.vitorpamplona.amethyst.ui.components.GenericLoadable -import junit.framework.TestCase.assertEquals import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.runBlocking +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith diff --git a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/DMFileDecryptionTest.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/DMFileDecryptionTest.kt index 7e3e34a6ec..9713d7dd4d 100644 --- a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/DMFileDecryptionTest.kt +++ b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/DMFileDecryptionTest.kt @@ -24,10 +24,10 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.amethyst.service.okhttp.EncryptedBlobInterceptor import com.vitorpamplona.amethyst.service.okhttp.EncryptionKeyCache import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray -import com.vitorpamplona.quartz.nip17Dm.files.encryption.AESGCM -import junit.framework.TestCase.assertEquals +import com.vitorpamplona.quartz.utils.ciphers.AESGCM import okhttp3.OkHttpClient import okhttp3.Request +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith diff --git a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt index 24cae52d3c..6f940370e1 100644 --- a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt +++ b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt @@ -41,7 +41,6 @@ import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip98HttpAuth.HTTPAuthorizationEvent import com.vitorpamplona.quartz.utils.sha256.sha256 -import junit.framework.TestCase.assertEquals import junit.framework.TestCase.fail import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -49,6 +48,7 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.runBlocking import okhttp3.OkHttpClient import org.junit.Assert +import org.junit.Assert.assertEquals import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith @@ -247,13 +247,6 @@ class ImageUploadTesting { testBase(ServerName("sovbit", "https://files.sovbit.host", ServerType.NIP96)) } - @Test() - @Ignore("Not Working anymore") - fun testVoidCat() = - runBlocking { - testBase(ServerName("void.cat", "https://void.cat", ServerType.NIP96)) - } - @Test() @Ignore("Returns invalid image size") fun testNostrPic() = diff --git a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/OkHttpOtsTest.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/OkHttpOtsTest.kt index 91f63f94d3..d11351b977 100644 --- a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/OkHttpOtsTest.kt +++ b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/OkHttpOtsTest.kt @@ -21,17 +21,15 @@ package com.vitorpamplona.amethyst import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip03Timestamp.OtsEvent -import com.vitorpamplona.quartz.nip03Timestamp.OtsResolver -import com.vitorpamplona.quartz.nip03Timestamp.ots.okhttp.OkHttpBitcoinExplorer -import com.vitorpamplona.quartz.nip03Timestamp.ots.okhttp.OkHttpCalendarBuilder -import com.vitorpamplona.quartz.nip03Timestamp.ots.okhttp.OtsBlockHeightCache -import junit.framework.TestCase.assertEquals +import com.vitorpamplona.quartz.nip03Timestamp.okhttp.OkHttpOtsResolverBuilder +import com.vitorpamplona.quartz.nip03Timestamp.ots.OtsBlockHeightCache import kotlinx.coroutines.runBlocking import okhttp3.OkHttpClient +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith @@ -45,51 +43,50 @@ class OkHttpOtsTest { val otsCache = OtsBlockHeightCache() val resolver = - OtsResolver( - OkHttpBitcoinExplorer( - baseAPI = OkHttpBitcoinExplorer.MEMPOOL_API_URL, - client = OkHttpClient.Builder().build(), - cache = otsCache, - ), - OkHttpCalendarBuilder { OkHttpClient.Builder().build() }, - ) + OkHttpOtsResolverBuilder( + otsCache, + ) { OkHttpClient.Builder().build() }.build() @Test - fun verifyNostrEvent() { - val ots = JsonMapper.fromJson(otsEvent) as OtsEvent - println(resolver.info(ots.otsByteArray())) - assertEquals(1707688818L, ots.verify(resolver)) - } + fun verifyNostrEvent() = + runBlocking { + val ots = OptimizedJsonMapper.fromJson(otsEvent) as OtsEvent + println(resolver.info(ots.otsByteArray())) + assertEquals(1707688818L, ots.verify(resolver)) + } @Test - fun verifyNostrEvent2() { - val ots = JsonMapper.fromJson(otsEvent2) as OtsEvent - println(resolver.info(ots.otsByteArray())) - assertEquals(1706322179L, ots.verify(resolver)) - } + fun verifyNostrEvent2() = + runBlocking { + val ots = OptimizedJsonMapper.fromJson(otsEvent2) as OtsEvent + println(resolver.info(ots.otsByteArray())) + assertEquals(1706322179L, ots.verify(resolver)) + } @Test - fun verifyNostrPendingEvent() { - val ots = JsonMapper.fromJson(otsPendingEvent) as OtsEvent - println(resolver.info(ots.otsByteArray())) - assertEquals(null, ots.verify(resolver)) - } + fun verifyNostrPendingEvent() = + runBlocking { + val ots = OptimizedJsonMapper.fromJson(otsPendingEvent) as OtsEvent + println(resolver.info(ots.otsByteArray())) + assertEquals(null, ots.verify(resolver)) + } @Test - fun createOTSEventAndVerify() { - val signer = NostrSignerInternal(KeyPair()) + fun createOTSEventAndVerify() = + runBlocking { + val signer = NostrSignerInternal(KeyPair()) - val otsFile = OtsEvent.stamp(otsEvent2Digest, resolver) + val otsFile = OtsEvent.stamp(otsEvent2Digest, resolver) - val ots = - runBlocking { - signer.sign(OtsEvent.build(otsEvent2Digest, otsFile)) - } + val ots = + runBlocking { + signer.sign(OtsEvent.build(otsEvent2Digest, otsFile)) + } - println(ots.toJson()) - println(resolver.info(ots.otsByteArray())) + println(ots.toJson()) + println(resolver.info(ots.otsByteArray())) - // Should not be valid because we need to wait for confirmations - assertEquals(null, ots.verify(resolver)) - } + // Should not be valid because we need to wait for confirmations + assertEquals(null, ots.verify(resolver)) + } } diff --git a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ThreadDualAxisChartAssemblerTest.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ThreadDualAxisChartAssemblerTest.kt index 99db5b6288..cce0af9913 100644 --- a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ThreadDualAxisChartAssemblerTest.kt +++ b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ThreadDualAxisChartAssemblerTest.kt @@ -27,21 +27,24 @@ import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.service.location.LocationState import com.vitorpamplona.amethyst.service.okhttp.OkHttpWebSocket +import com.vitorpamplona.amethyst.service.relayClient.reqCommand.nwc.NWCPaymentFilterAssembler +import com.vitorpamplona.amethyst.ui.screen.loggedIn.EmptyOtsResolverBuilder import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.dal.ThreadFeedFilter import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.crypto.verify +import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper +import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.verify +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import junit.framework.TestCase -import junit.framework.TestCase.assertEquals import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking import okhttp3.OkHttpClient +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith @@ -49,24 +52,28 @@ import org.junit.runner.RunWith class ThreadDualAxisChartAssemblerTest { companion object { val keyPair = KeyPair() + val client = + NostrClient( + OkHttpWebSocket.Builder { + OkHttpClient + .Builder() + .followRedirects(true) + .followSslRedirects(true) + .build() + }, + CoroutineScope(Dispatchers.IO + SupervisorJob()), + ) + val account = Account( settings = AccountSettings(keyPair = keyPair), signer = NostrSignerInternal(keyPair), - scope = CoroutineScope(Dispatchers.IO + SupervisorJob()), geolocationFlow = MutableStateFlow(LocationState.LocationResult.Loading), + nwcFilterAssembler = NWCPaymentFilterAssembler(client), + otsResolverBuilder = EmptyOtsResolverBuilder, cache = LocalCache, - client = - NostrClient( - OkHttpWebSocket.Builder { - OkHttpClient - .Builder() - .followRedirects(true) - .followSslRedirects(true) - .build() - }, - CoroutineScope(Dispatchers.IO + SupervisorJob()), - ), + client = client, + scope = CoroutineScope(Dispatchers.IO + SupervisorJob()), ) val db = @@ -148,7 +155,7 @@ class ThreadDualAxisChartAssemblerTest { fun threadOrderTest() = runBlocking { val eventArray = - JsonMapper.mapper.readValue>(db) as List + Event.fromJson(header) + JacksonMapper.mapper.readValue>(db) + Event.fromJson(header) var counter = 0 eventArray.forEach { @@ -168,7 +175,7 @@ class ThreadDualAxisChartAssemblerTest { val filter = ThreadFeedFilter(account, naddr.toTag()) val calculatedFeed = filter.feed() - val expecteedOrder = + val expectedOrder = listOf( "30023:6e468422dfb74a5738702a8823b9b28168abab8655faacb6853cd0ee15deee93:1680612926599", "e15b386824fbfdcbf1b50b8860f03062cef534a3ea5339cc837536fb2a58465e", @@ -210,8 +217,8 @@ class ThreadDualAxisChartAssemblerTest { "7a18dda355525d468b31bba4fa947cba98cc19048d4a3099d5e9ba045d878c26", ) - for (i in expecteedOrder.indices) { - assertEquals(expecteedOrder[i], calculatedFeed[i].idHex) + for (i in expectedOrder.indices) { + assertEquals(expectedOrder[i], calculatedFeed[i].idHex) } } } diff --git a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/URIParserTest.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/URIParserTest.kt index db649c1982..200a494213 100644 --- a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/URIParserTest.kt +++ b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/URIParserTest.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst import com.vitorpamplona.amethyst.ui.navigation.findParameterValue -import junit.framework.TestCase.assertEquals +import org.junit.Assert.assertEquals import org.junit.Test import java.net.URI diff --git a/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushDistributorHandler.kt b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushDistributorHandler.kt index 128c694202..47df83e681 100644 --- a/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushDistributorHandler.kt +++ b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushDistributorHandler.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.service.notifications import android.content.Context import android.content.pm.PackageManager import android.os.Build -import android.util.Log import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.quartz.utils.Log import org.unifiedpush.android.connector.UnifiedPush interface PushDistributorActions { diff --git a/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushMessageReceiver.kt b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushMessageReceiver.kt index 1d54873fbc..ce1d4428e7 100644 --- a/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushMessageReceiver.kt +++ b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/service/notifications/PushMessageReceiver.kt @@ -22,13 +22,13 @@ package com.vitorpamplona.amethyst.service.notifications import android.app.NotificationManager import android.content.Context -import android.util.Log import android.util.LruCache import androidx.core.content.ContextCompat import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt index 0168e90a1f..8d0d989bef 100644 --- a/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt +++ b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt @@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.components import android.Manifest import android.os.Build -import android.util.Log import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row @@ -64,6 +63,7 @@ import com.vitorpamplona.amethyst.ui.components.SpinnerSelectionDialog import com.vitorpamplona.amethyst.ui.components.TitleExplainer import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsRow import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt index 9862203d48..d686147ade 100644 --- a/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt +++ b/amethyst/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt @@ -28,7 +28,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists @Composable fun TranslatableRichTextViewer( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt index 7ae55fbab8..da67134d81 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt @@ -21,8 +21,8 @@ package com.vitorpamplona.amethyst import android.app.Application -import android.util.Log import com.vitorpamplona.amethyst.service.logging.Logging +import com.vitorpamplona.quartz.utils.Log class Amethyst : Application() { companion object { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt index 29c888d45c..906c3b510c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt @@ -22,13 +22,13 @@ package com.vitorpamplona.amethyst import android.content.ContentResolver import android.content.Context -import android.util.Log import androidx.security.crypto.EncryptedSharedPreferences import coil3.disk.DiskCache import coil3.memory.MemoryCache import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.accountsCache.AccountCacheState import com.vitorpamplona.amethyst.model.nip03Timestamp.IncomingOtsEventVerifier +import com.vitorpamplona.amethyst.model.nip03Timestamp.TorAwareOkHttpOtsResolverBuilder import com.vitorpamplona.amethyst.model.nip11RelayInfo.Nip11CachedRetriever import com.vitorpamplona.amethyst.model.preferences.TorSharedPreferences import com.vitorpamplona.amethyst.model.preferences.UiSharedPreferences @@ -60,8 +60,8 @@ import com.vitorpamplona.amethyst.ui.tor.TorManager import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient import com.vitorpamplona.quartz.nip03Timestamp.VerificationStateCache -import com.vitorpamplona.quartz.nip03Timestamp.ots.okhttp.OkHttpOtsResolverBuilder -import com.vitorpamplona.quartz.nip03Timestamp.ots.okhttp.OtsBlockHeightCache +import com.vitorpamplona.quartz.nip03Timestamp.ots.OtsBlockHeightCache +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -146,8 +146,8 @@ class AppModules( // Application-wide block height request cache val otsBlockHeightCache by lazy { OtsBlockHeightCache() } - val otsResolverBuilder: OkHttpOtsResolverBuilder = - OkHttpOtsResolverBuilder( + val otsResolverBuilder: TorAwareOkHttpOtsResolverBuilder = + TorAwareOkHttpOtsResolverBuilder( roleBasedHttpClientBuilder::okHttpClientForMoney, roleBasedHttpClientBuilder::shouldUseTorForMoneyOperations, otsBlockHeightCache, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/DebugUtils.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/DebugUtils.kt index 9224b615d9..f10327af16 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/DebugUtils.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/DebugUtils.kt @@ -24,9 +24,9 @@ import android.app.ActivityManager import android.content.Context import android.content.pm.ApplicationInfo import android.os.Debug -import android.util.Log import androidx.core.content.getSystemService import com.vitorpamplona.amethyst.model.LocalCache +import com.vitorpamplona.quartz.utils.Log import kotlin.time.DurationUnit import kotlin.time.measureTimedValue diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 4165bc3951..8a48aca824 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -23,10 +23,8 @@ package com.vitorpamplona.amethyst import android.annotation.SuppressLint import android.content.Context import android.content.SharedPreferences -import android.util.Log import androidx.compose.runtime.Immutable import androidx.core.content.edit -import com.fasterxml.jackson.module.kotlin.readValue import com.vitorpamplona.amethyst.model.ALL_FOLLOWS import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.GLOBAL_FOLLOWS @@ -37,10 +35,11 @@ import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerName import com.vitorpamplona.quartz.experimental.ephemChat.list.EphemeralChatListEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.JsonMapper +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import com.vitorpamplona.quartz.nip17Dm.settings.ChatMessageRelayListEvent @@ -57,13 +56,16 @@ import com.vitorpamplona.quartz.nip51Lists.relayLists.TrustedRelayListEvent import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent import com.vitorpamplona.quartz.nip72ModCommunities.follow.CommunityListEvent import com.vitorpamplona.quartz.nip78AppData.AppSpecificDataEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext +import kotlinx.serialization.Serializable import java.io.File +import kotlin.jvm.java // Release mode (!BuildConfig.DEBUG) always uses encrypted preferences // To use plaintext SharedPreferences for debugging, set this to true @@ -72,6 +74,7 @@ private const val DEBUG_PLAINTEXT_PREFERENCES = false private const val DEBUG_PREFERENCES_NAME = "debug_prefs" @Immutable +@Serializable data class AccountInfo( val npub: String, val hasPrivKey: Boolean, @@ -161,7 +164,7 @@ object LocalPreferences { with(encryptedPreferences()) { val newSystemOfAccounts = getString(PrefKeys.ALL_ACCOUNT_INFO, "[]")?.let { - JsonMapper.mapper.readValue>(it) + JsonMapper.fromJson>(it) } if (!newSystemOfAccounts.isNullOrEmpty()) { @@ -181,7 +184,9 @@ object LocalPreferences { savedAccounts.emit(migrated) - edit { putString(PrefKeys.ALL_ACCOUNT_INFO, JsonMapper.mapper.writeValueAsString(savedAccounts.value)) } + edit { + putString(PrefKeys.ALL_ACCOUNT_INFO, JsonMapper.toJson(migrated)) + } } } } @@ -201,7 +206,7 @@ object LocalPreferences { .edit { putString( PrefKeys.ALL_ACCOUNT_INFO, - JsonMapper.mapper.writeValueAsString(accounts.filter { !it.isTransient }), + JsonMapper.toJson(accounts.filter { !it.isTransient }), ) } } @@ -308,7 +313,7 @@ object LocalPreferences { putString( PrefKeys.DEFAULT_FILE_SERVER, - JsonMapper.mapper.writeValueAsString(settings.defaultFileServer), + JsonMapper.toJson(settings.defaultFileServer), ) putString(PrefKeys.DEFAULT_HOME_FOLLOW_LIST, settings.defaultHomeFollowList.value) putString(PrefKeys.DEFAULT_STORIES_FOLLOW_LIST, settings.defaultStoriesFollowList.value) @@ -320,72 +325,16 @@ object LocalPreferences { PrefKeys.DEFAULT_DISCOVERY_FOLLOW_LIST, settings.defaultDiscoveryFollowList.value, ) - putString( - PrefKeys.ZAP_PAYMENT_REQUEST_SERVER, - JsonMapper.mapper.writeValueAsString(settings.zapPaymentRequest.value?.denormalize()), - ) - if (settings.backupContactList != null) { - putString( - PrefKeys.LATEST_CONTACT_LIST, - JsonMapper.mapper.writeValueAsString(settings.backupContactList), - ) - } else { - remove(PrefKeys.LATEST_CONTACT_LIST) - } + putOrRemove(PrefKeys.ZAP_PAYMENT_REQUEST_SERVER, settings.zapPaymentRequest.value?.denormalize()) - if (settings.backupUserMetadata != null) { - putString( - PrefKeys.LATEST_USER_METADATA, - JsonMapper.mapper.writeValueAsString(settings.backupUserMetadata), - ) - } else { - remove(PrefKeys.LATEST_USER_METADATA) - } + putOrRemove(PrefKeys.LATEST_CONTACT_LIST, settings.backupContactList) - if (settings.backupDMRelayList != null) { - putString( - PrefKeys.LATEST_DM_RELAY_LIST, - JsonMapper.mapper.writeValueAsString(settings.backupDMRelayList), - ) - } else { - remove(PrefKeys.LATEST_DM_RELAY_LIST) - } - - if (settings.backupNIP65RelayList != null) { - putString( - PrefKeys.LATEST_NIP65_RELAY_LIST, - JsonMapper.mapper.writeValueAsString(settings.backupNIP65RelayList), - ) - } else { - remove(PrefKeys.LATEST_NIP65_RELAY_LIST) - } - - if (settings.backupSearchRelayList != null) { - putString( - PrefKeys.LATEST_SEARCH_RELAY_LIST, - JsonMapper.mapper.writeValueAsString(settings.backupSearchRelayList), - ) - } else { - remove(PrefKeys.LATEST_SEARCH_RELAY_LIST) - } - - if (settings.backupBlockedRelayList != null) { - putString( - PrefKeys.LATEST_BLOCKED_RELAY_LIST, - JsonMapper.mapper.writeValueAsString(settings.backupBlockedRelayList), - ) - } else { - remove(PrefKeys.LATEST_BLOCKED_RELAY_LIST) - } - - if (settings.backupTrustedRelayList != null) { - putString( - PrefKeys.LATEST_TRUSTED_RELAY_LIST, - JsonMapper.mapper.writeValueAsString(settings.backupTrustedRelayList), - ) - } else { - remove(PrefKeys.LATEST_TRUSTED_RELAY_LIST) - } + putOrRemove(PrefKeys.LATEST_USER_METADATA, settings.backupUserMetadata) + putOrRemove(PrefKeys.LATEST_DM_RELAY_LIST, settings.backupDMRelayList) + putOrRemove(PrefKeys.LATEST_NIP65_RELAY_LIST, settings.backupNIP65RelayList) + putOrRemove(PrefKeys.LATEST_SEARCH_RELAY_LIST, settings.backupSearchRelayList) + putOrRemove(PrefKeys.LATEST_BLOCKED_RELAY_LIST, settings.backupBlockedRelayList) + putOrRemove(PrefKeys.LATEST_TRUSTED_RELAY_LIST, settings.backupTrustedRelayList) if (settings.localRelayServers.value.isNotEmpty()) { putStringSet(PrefKeys.LOCAL_RELAY_SERVERS, settings.localRelayServers.value) @@ -393,77 +342,15 @@ object LocalPreferences { remove(PrefKeys.LOCAL_RELAY_SERVERS) } - if (settings.backupMuteList != null) { - putString( - PrefKeys.LATEST_MUTE_LIST, - JsonMapper.mapper.writeValueAsString(settings.backupMuteList), - ) - } else { - remove(PrefKeys.LATEST_MUTE_LIST) - } + putOrRemove(PrefKeys.LATEST_MUTE_LIST, settings.backupMuteList) + putOrRemove(PrefKeys.LATEST_PRIVATE_HOME_RELAY_LIST, settings.backupPrivateHomeRelayList) + putOrRemove(PrefKeys.LATEST_APP_SPECIFIC_DATA, settings.backupAppSpecificData) - if (settings.backupPrivateHomeRelayList != null) { - putString( - PrefKeys.LATEST_PRIVATE_HOME_RELAY_LIST, - JsonMapper.mapper.writeValueAsString(settings.backupPrivateHomeRelayList), - ) - } else { - remove(PrefKeys.LATEST_PRIVATE_HOME_RELAY_LIST) - } - - if (settings.backupAppSpecificData != null) { - putString( - PrefKeys.LATEST_APP_SPECIFIC_DATA, - JsonMapper.mapper.writeValueAsString(settings.backupAppSpecificData), - ) - } else { - remove(PrefKeys.LATEST_APP_SPECIFIC_DATA) - } - - if (settings.backupChannelList != null) { - putString( - PrefKeys.LATEST_CHANNEL_LIST, - JsonMapper.mapper.writeValueAsString(settings.backupChannelList), - ) - } else { - remove(PrefKeys.LATEST_CHANNEL_LIST) - } - - if (settings.backupCommunityList != null) { - putString( - PrefKeys.LATEST_COMMUNITY_LIST, - JsonMapper.mapper.writeValueAsString(settings.backupCommunityList), - ) - } else { - remove(PrefKeys.LATEST_COMMUNITY_LIST) - } - - if (settings.backupHashtagList != null) { - putString( - PrefKeys.LATEST_HASHTAG_LIST, - JsonMapper.mapper.writeValueAsString(settings.backupHashtagList), - ) - } else { - remove(PrefKeys.LATEST_HASHTAG_LIST) - } - - if (settings.backupGeohashList != null) { - putString( - PrefKeys.LATEST_GEOHASH_LIST, - JsonMapper.mapper.writeValueAsString(settings.backupGeohashList), - ) - } else { - remove(PrefKeys.LATEST_GEOHASH_LIST) - } - - if (settings.backupEphemeralChatList != null) { - putString( - PrefKeys.LATEST_EPHEMERAL_LIST, - JsonMapper.mapper.writeValueAsString(settings.backupEphemeralChatList), - ) - } else { - remove(PrefKeys.LATEST_EPHEMERAL_LIST) - } + putOrRemove(PrefKeys.LATEST_CHANNEL_LIST, settings.backupChannelList) + putOrRemove(PrefKeys.LATEST_COMMUNITY_LIST, settings.backupCommunityList) + putOrRemove(PrefKeys.LATEST_HASHTAG_LIST, settings.backupHashtagList) + putOrRemove(PrefKeys.LATEST_GEOHASH_LIST, settings.backupGeohashList) + putOrRemove(PrefKeys.LATEST_EPHEMERAL_LIST, settings.backupEphemeralChatList) putBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, settings.hideDeleteRequestDialog) putBoolean(PrefKeys.HIDE_NIP_17_WARNING_DIALOG, settings.hideNIP17WarningDialog) @@ -480,13 +367,13 @@ object LocalPreferences { putString( PrefKeys.LAST_READ_PER_ROUTE, - JsonMapper.mapper.writeValueAsString(regularMap), + JsonMapper.toJson(regularMap), ) putStringSet(PrefKeys.HAS_DONATED_IN_VERSION, settings.hasDonatedInVersion.value) putString( PrefKeys.PENDING_ATTESTATIONS, - JsonMapper.mapper.writeValueAsString(settings.pendingAttestations.value), + JsonMapper.toJson(settings.pendingAttestations.value), ) } } @@ -502,7 +389,7 @@ object LocalPreferences { ) { Log.d("LocalPreferences", "Saving to shared settings") prefs.edit { - putString(PrefKeys.SHARED_SETTINGS, JsonMapper.mapper.writeValueAsString(sharedSettings)) + putString(PrefKeys.SHARED_SETTINGS, JsonMapper.toJson(sharedSettings)) } } @@ -511,7 +398,7 @@ object LocalPreferences { with(prefs) { return try { getString(PrefKeys.SHARED_SETTINGS, "{}")?.let { - JsonMapper.mapper.readValue(it) + JsonMapper.fromJson(it) } } catch (e: Throwable) { if (e is CancellationException) throw e @@ -643,7 +530,7 @@ object LocalPreferences { return result } - private inline fun SharedPreferences.parseOrNull(key: String): T? { + private inline fun SharedPreferences.parseOrNull(key: String): T? { val value = getString(key, null) if (value.isNullOrEmpty() || value == "null") { return null @@ -652,7 +539,7 @@ object LocalPreferences { if (T::class.java.isInstance(Event::class.java)) { Event.fromJson(value) as T? } else { - JsonMapper.mapper.readValue(value) + JsonMapper.fromJson(value) } } catch (e: Throwable) { if (e is CancellationException) throw e @@ -674,4 +561,26 @@ object LocalPreferences { null } } + + fun SharedPreferences.Editor.putOrRemove( + key: String, + event: Any?, + ) { + if (event != null) { + putString(key, JsonMapper.toJson(event)) + } else { + remove(key) + } + } + + fun SharedPreferences.Editor.putOrRemove( + key: String, + event: Event?, + ) { + if (event != null) { + putString(key, OptimizedJsonMapper.toJson(event)) + } else { + remove(key) + } + } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 53037cb48c..094850ab3f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model -import android.util.Log import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.LocalPreferences @@ -204,6 +203,7 @@ import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag import com.vitorpamplona.quartz.nip98HttpAuth.HTTPAuthorizationEvent import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceEvent import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceReplyEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers @@ -802,27 +802,27 @@ class Account( } } - fun broadcast(note: Note) { - note.event?.let { - if (it is WrappedEvent && it.host != null) { + suspend fun broadcast(note: Note) { + note.event?.let { noteEvent -> + if (noteEvent is WrappedEvent && noteEvent.host != null) { // download the event and send it. - it.host?.let { host -> - client.downloadFirstEvent( - filters = - note.relays.associateWith { relay -> - listOf( - Filter( - ids = listOf(host.id), - ), - ) - }, - onResponse = { - client.send(it, computeRelayListToBroadcast(it)) - }, - ) + noteEvent.host?.let { host -> + client + .downloadFirstEvent( + filters = + note.relays.associateWith { relay -> + listOf( + Filter( + ids = listOf(host.id), + ), + ) + }, + )?.let { downloadedEvent -> + client.send(downloadedEvent, computeRelayListToBroadcast(downloadedEvent)) + } } } else { - client.send(it, computeRelayListToBroadcast(note)) + client.send(noteEvent, computeRelayListToBroadcast(note)) } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSyncedSettingsInternal.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSyncedSettingsInternal.kt index 6efe26d4af..8b66d2ce1e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSyncedSettingsInternal.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSyncedSettingsInternal.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.model import android.content.res.Resources import androidx.core.os.ConfigurationCompat import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent +import kotlinx.serialization.Serializable import java.util.Locale val DefaultReactions = @@ -47,6 +48,7 @@ fun getLanguagesSpokenByUser(): Set { return codedList } +@Serializable class AccountSyncedSettingsInternal( val reactions: AccountReactionPreferencesInternal = AccountReactionPreferencesInternal(), val zaps: AccountZapPreferencesInternal = AccountZapPreferencesInternal(), @@ -54,21 +56,25 @@ class AccountSyncedSettingsInternal( val security: AccountSecurityPreferencesInternal = AccountSecurityPreferencesInternal(), ) +@Serializable class AccountReactionPreferencesInternal( var reactionChoices: List = DefaultReactions, ) +@Serializable class AccountZapPreferencesInternal( var zapAmountChoices: List = DefaultZapAmounts, val defaultZapType: LnZapEvent.ZapType = LnZapEvent.ZapType.PUBLIC, ) +@Serializable class AccountLanguagePreferencesInternal( var dontTranslateFrom: Set = getLanguagesSpokenByUser(), var languagePreferences: Map = mapOf(), var translateTo: String = Locale.getDefault().language, ) +@Serializable class AccountSecurityPreferencesInternal( val showSensitiveContent: Boolean? = null, var warnAboutPostsWithReports: Boolean = true, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt index 4b2defdcb1..b9bdfdcb94 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt @@ -20,18 +20,18 @@ */ package com.vitorpamplona.amethyst.model -import android.util.Log import android.util.LruCache import com.vitorpamplona.amethyst.ui.note.njumpLink +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStats import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip19Bech32.Nip19Parser import com.vitorpamplona.quartz.nip19Bech32.entities.NAddress import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.flow.MutableStateFlow data class Spammer( @@ -65,7 +65,7 @@ class AntiSpamFilter { // really long, make it ok. // The idea here is to avoid considering repeated "@Bot, command" messages spam, while still // blocking repeated "lnbc..." invoices or fishing urls - if (event.content.length < 180 && event.content.startsWith("nostr:") && Nip19Parser.nip19regex.matcher(event.content).find()) return false + if (event.content.length < 180 && event.content.startsWith("nostr:") && Nip19Parser.hasAny(event.content)) return false // double list strategy: // if duplicated, it goes into spam. 1000 spam messages are saved into the spam list. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt index e711e8fe1b..336610ae94 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Channel.kt @@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder import com.vitorpamplona.amethyst.ui.dal.ListChange import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.utils.cache.LargeCache import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/HashtagIcon.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/HashtagIcon.kt index b000d16c02..468cedc6f9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/HashtagIcon.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/HashtagIcon.kt @@ -51,7 +51,7 @@ import com.vitorpamplona.amethyst.ui.components.HashTag import com.vitorpamplona.amethyst.ui.components.RenderRegular import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList @Preview @Composable diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/LargeSoftCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LargeSoftCache.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/LargeSoftCache.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/model/LargeSoftCache.kt index 6846f275c8..a513bedc8b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/LargeSoftCache.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LargeSoftCache.kt @@ -18,8 +18,9 @@ * 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.quartz.utils +package com.vitorpamplona.amethyst.model +import com.vitorpamplona.quartz.utils.cache.CacheOperations import java.lang.ref.WeakReference import java.util.concurrent.ConcurrentSkipListMap import java.util.function.BiConsumer diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt index ae60c29665..172ef6c1db 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model -import android.util.Log import android.util.LruCache import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.Amethyst @@ -52,12 +51,14 @@ import com.vitorpamplona.quartz.experimental.profileGallery.ProfileGalleryEntryE import com.vitorpamplona.quartz.experimental.publicMessages.PublicMessageEvent import com.vitorpamplona.quartz.experimental.relationshipStatus.ContactCardEvent import com.vitorpamplona.quartz.experimental.zapPolls.PollNoteEvent -import com.vitorpamplona.quartz.nip01Core.checkSignature +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.tagValueContains +import com.vitorpamplona.quartz.nip01Core.crypto.checkSignature +import com.vitorpamplona.quartz.nip01Core.crypto.verify import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.hints.HintIndexer @@ -66,16 +67,14 @@ import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.isLocalHost -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address -import com.vitorpamplona.quartz.nip01Core.tags.addressables.taggedAddresses +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.taggedAddresses import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.events.GenericETag import com.vitorpamplona.quartz.nip01Core.tags.events.forEachTaggedEventId import com.vitorpamplona.quartz.nip01Core.tags.events.isTaggedEvent import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUsers -import com.vitorpamplona.quartz.nip01Core.verify import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import com.vitorpamplona.quartz.nip03Timestamp.OtsEvent import com.vitorpamplona.quartz.nip03Timestamp.VerificationState @@ -184,9 +183,9 @@ import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceEvent import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceReplyEvent import com.vitorpamplona.quartz.nipB7Blossom.BlossomServersEvent import com.vitorpamplona.quartz.utils.Hex -import com.vitorpamplona.quartz.utils.LargeCache -import com.vitorpamplona.quartz.utils.LargeSoftCache +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils +import com.vitorpamplona.quartz.utils.cache.LargeCache import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CancellationException @@ -2151,7 +2150,7 @@ object LocalCache : ILocalCache { .toImmutableList() } - fun findEarliestOtsForNote( + suspend fun findEarliestOtsForNote( note: Note, otsVerifCache: VerificationStateCache, ): Long? { @@ -2160,13 +2159,29 @@ object LocalCache : ILocalCache { var minTime: Long? = null val time = TimeUtils.now() - notes.forEach { _, item -> - val noteEvent = item.event - if ((noteEvent is OtsEvent && noteEvent.isTaggedEvent(note.idHex) && !noteEvent.isExpirationBefore(time))) { - (otsVerifCache.cacheVerify(noteEvent) as? VerificationState.Verified)?.verifiedTime?.let { stampedTime -> - if (minTime == null || stampedTime < (minTime ?: Long.MAX_VALUE)) { - minTime = stampedTime + val candidates = + notes.mapNotNull { _, item -> + val noteEvent = item.event + if ((noteEvent is OtsEvent && noteEvent.isTaggedEvent(note.idHex) && !noteEvent.isExpirationBefore(time))) { + val cachedTime = (otsVerifCache.justCache(noteEvent) as? VerificationState.Verified)?.verifiedTime + if (cachedTime != null) { + if (minTime == null || cachedTime < (minTime ?: Long.MAX_VALUE)) { + minTime = cachedTime + } + null + } else { + // tries to verify again + noteEvent } + } else { + null + } + } + + candidates.forEach { noteEvent -> + (otsVerifCache.cacheVerify(noteEvent) as? VerificationState.Verified)?.verifiedTime?.let { stampedTime -> + if (minTime == null || stampedTime < (minTime ?: Long.MAX_VALUE)) { + minTime = stampedTime } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/MiniFhir.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/MiniFhir.kt index f5150e4bd7..1e56a62a82 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/MiniFhir.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/MiniFhir.kt @@ -20,12 +20,13 @@ */ package com.vitorpamplona.amethyst.model -import android.util.Log import androidx.compose.runtime.Stable import com.fasterxml.jackson.annotation.JsonSubTypes import com.fasterxml.jackson.annotation.JsonTypeInfo import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.ImmutableMap import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.toImmutableMap @@ -160,7 +161,7 @@ fun parseResourceBundleOrNull(json: String): FhirElementDatabase? { jacksonObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) return try { - val resource = mapper.readValue(json, Resource::class.java) + val resource = mapper.readValue(json) val db = when (resource) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Note.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Note.kt index b203748b16..fd4d927f7c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Note.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Note.kt @@ -31,17 +31,17 @@ import com.vitorpamplona.amethyst.ui.note.toShortDisplay import com.vitorpamplona.quartz.experimental.bounties.addedRewardValue import com.vitorpamplona.quartz.experimental.bounties.hasAdditionalReward import com.vitorpamplona.quartz.lightning.LnInvoiceUtil +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.events.EventReference import com.vitorpamplona.quartz.nip01Core.tags.hashtags.anyHashTag import com.vitorpamplona.quartz.nip01Core.tags.publishedAt.PublishedAtProvider -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/ThreadAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/ThreadAssembler.kt index 7026aca5a5..03ba05a3d6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/ThreadAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/ThreadAssembler.kt @@ -22,8 +22,8 @@ package com.vitorpamplona.amethyst.model import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.service.checkNotInMainThread +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent import com.vitorpamplona.quartz.nip18Reposts.RepostEvent import kotlinx.collections.immutable.ImmutableSet diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/UiSettings.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/UiSettings.kt index 3a1b5c1a52..cfd116e512 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/UiSettings.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/UiSettings.kt @@ -22,8 +22,10 @@ package com.vitorpamplona.amethyst.model import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.R +import kotlinx.serialization.Serializable @Stable +@Serializable data class UiSettings( val theme: ThemeType = ThemeType.SYSTEM, val preferredLanguage: String? = null, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/User.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/User.kt index a91dd6e053..80061efe03 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/User.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/User.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.ui.note.toShortDisplay import com.vitorpamplona.quartz.lightning.Lud06 import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import com.vitorpamplona.quartz.nip01Core.metadata.UserMetadata import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @@ -33,7 +34,6 @@ import com.vitorpamplona.quartz.nip01Core.tags.hashtags.isTaggedHash import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists import com.vitorpamplona.quartz.nip17Dm.settings.ChatMessageRelayListEvent import com.vitorpamplona.quartz.nip19Bech32.entities.NProfile import com.vitorpamplona.quartz.nip19Bech32.toNpub diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/accountsCache/AccountCacheState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/accountsCache/AccountCacheState.kt index 700e5fdc38..d16c67b3d0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/accountsCache/AccountCacheState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/accountsCache/AccountCacheState.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.model.accountsCache import android.content.ContentResolver -import android.util.Log import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.LocalCache @@ -34,6 +33,7 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip03Timestamp.OtsResolverBuilder import com.vitorpamplona.quartz.nip55AndroidSigner.client.NostrSignerExternal +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/edits/PrivateStorageRelayListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/edits/PrivateStorageRelayListState.kt index 89d3eaa0ac..dfad190c95 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/edits/PrivateStorageRelayListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/edits/PrivateStorageRelayListState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model.edits -import android.util.Log import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note @@ -28,6 +27,7 @@ import com.vitorpamplona.amethyst.model.NoteState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip37Drafts.privateOutbox.PrivateOutboxRelayListEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/emphChat/EphemeralChatListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/emphChat/EphemeralChatListState.kt index 6e87695705..fab0e395e4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/emphChat/EphemeralChatListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/emphChat/EphemeralChatListState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model.emphChat -import android.util.Log import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note @@ -28,6 +27,7 @@ import com.vitorpamplona.amethyst.model.NoteState import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId import com.vitorpamplona.quartz.experimental.ephemChat.list.EphemeralChatListEvent import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/UserMetadataState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/UserMetadataState.kt index 0061c0385f..186419e348 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/UserMetadataState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip01UserMetadata/UserMetadataState.kt @@ -20,13 +20,13 @@ */ package com.vitorpamplona.amethyst.model.nip01UserMetadata -import android.util.Log import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.UserState import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/FollowListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/FollowListState.kt index 574a2345ff..a36abd2801 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/FollowListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip02FollowLists/FollowListState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model.nip02FollowLists -import android.util.Log import androidx.compose.runtime.Immutable import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.LocalCache @@ -32,6 +31,7 @@ import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import com.vitorpamplona.quartz.nip02FollowList.tags.ContactTag import com.vitorpamplona.quartz.nip73ExternalIds.location.GeohashId import com.vitorpamplona.quartz.nip73ExternalIds.topics.HashtagId +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/IncomingOtsEventVerifier.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/IncomingOtsEventVerifier.kt index d4cc44f705..df51825bf0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/IncomingOtsEventVerifier.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/IncomingOtsEventVerifier.kt @@ -25,7 +25,9 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.quartz.nip03Timestamp.OtsEvent import com.vitorpamplona.quartz.nip03Timestamp.VerificationStateCache import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn @@ -37,14 +39,17 @@ class IncomingOtsEventVerifier( val verifying = cache.live.newEventBundles .onEach { newNotes -> - newNotes.forEach(::consume) - }.stateIn( + newNotes.forEach { + consume(it) + } + }.flowOn(Dispatchers.Default) + .stateIn( scope, SharingStarted.Eagerly, null, ) - fun consume(note: Note) { + suspend fun consume(note: Note) { note.event?.let { event -> if (event is OtsEvent) { otsVerifCache.cacheVerify(event) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/OtsState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/OtsState.kt index faae8ee708..d941acebf1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/OtsState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/OtsState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model.nip03Timestamp -import android.util.Log import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note @@ -28,6 +27,7 @@ import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip03Timestamp.OtsEvent import com.vitorpamplona.quartz.nip03Timestamp.OtsResolverBuilder +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.update @@ -85,7 +85,7 @@ class OtsState( return settings.pendingAttestations.value[id] != null } - fun timestamp(note: Note) { + suspend fun timestamp(note: Note) { if (note.isDraft()) return val id = note.event?.id ?: note.idHex diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/TorAwareOkHttpOtsResolverBuilder.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/TorAwareOkHttpOtsResolverBuilder.kt new file mode 100644 index 0000000000..b86a8c77b9 --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/TorAwareOkHttpOtsResolverBuilder.kt @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2025 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.amethyst.model.nip03Timestamp + +import com.vitorpamplona.quartz.nip03Timestamp.OtsResolver +import com.vitorpamplona.quartz.nip03Timestamp.OtsResolverBuilder +import com.vitorpamplona.quartz.nip03Timestamp.okhttp.OkHttpBitcoinExplorer +import com.vitorpamplona.quartz.nip03Timestamp.okhttp.OkHttpCalendar +import com.vitorpamplona.quartz.nip03Timestamp.ots.OtsBlockHeightCache +import okhttp3.OkHttpClient + +class TorAwareOkHttpOtsResolverBuilder( + val okHttpClient: (url: String) -> OkHttpClient, + val isTorActive: (url: String) -> Boolean, + val cache: OtsBlockHeightCache, +) : OtsResolverBuilder { + fun getAPI(usingTor: Boolean) = + if (usingTor) { + OkHttpBitcoinExplorer.Companion.MEMPOOL_API_URL + } else { + OkHttpBitcoinExplorer.Companion.BLOCKSTREAM_API_URL + } + + override fun build(): OtsResolver = + OtsResolver( + explorer = + OkHttpBitcoinExplorer( + baseUrl = { + getAPI(usingTor = isTorActive(OkHttpBitcoinExplorer.Companion.MEMPOOL_API_URL)) + }, + client = okHttpClient(OkHttpBitcoinExplorer.Companion.MEMPOOL_API_URL), + cache = cache, + ), + calendar = OkHttpCalendar(okHttpClient), + ) +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip11RelayInfo/LoadRelayInfo.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip11RelayInfo/LoadRelayInfo.kt index 94aba84e2a..4ed3eb50d4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip11RelayInfo/LoadRelayInfo.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip11RelayInfo/LoadRelayInfo.kt @@ -20,13 +20,13 @@ */ package com.vitorpamplona.amethyst.model.nip11RelayInfo -import android.util.Log import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.produceState import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation +import com.vitorpamplona.quartz.utils.Log @Composable fun loadRelayInfo(relay: NormalizedRelayUrl): State = loadRelayInfo(relay, Amethyst.instance.nip11Cache) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip11RelayInfo/Nip11Retriever.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip11RelayInfo/Nip11Retriever.kt index 04892f9085..fd4bab976f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip11RelayInfo/Nip11Retriever.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip11RelayInfo/Nip11Retriever.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.amethyst.model.nip11RelayInfo -import android.util.Log import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.toHttp import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip17Dms/DmRelayListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip17Dms/DmRelayListState.kt index 842072115b..f582734cfc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip17Dms/DmRelayListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip17Dms/DmRelayListState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model.nip17Dms -import android.util.Log import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note @@ -28,6 +27,7 @@ import com.vitorpamplona.amethyst.model.NoteState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip17Dm.settings.ChatMessageRelayListEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip28PublicChats/PublicChatChannel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip28PublicChats/PublicChatChannel.kt index 5f1214f87b..75fa41af7e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip28PublicChats/PublicChatChannel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip28PublicChats/PublicChatChannel.kt @@ -25,10 +25,10 @@ import com.vitorpamplona.amethyst.model.Channel import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.note.toShortDisplay +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHintOptional -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelMetadataEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip28PublicChats/PublicChatListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip28PublicChats/PublicChatListState.kt index 70b4505ce3..d30bc45512 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip28PublicChats/PublicChatListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip28PublicChats/PublicChatListState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model.nip28PublicChats -import android.util.Log import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note @@ -29,6 +28,7 @@ import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip28PublicChat.list.ChannelListEvent import com.vitorpamplona.quartz.nip28PublicChat.list.tags.ChannelTag +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip30CustomEmojis/EmojiPackState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip30CustomEmojis/EmojiPackState.kt index 38cf0aedd3..0fdb4793ae 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip30CustomEmojis/EmojiPackState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip30CustomEmojis/EmojiPackState.kt @@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.NoteState import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner -import com.vitorpamplona.quartz.nip01Core.tags.addressables.taggedAddresses +import com.vitorpamplona.quartz.nip01Core.tags.aTag.taggedAddresses import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent import com.vitorpamplona.quartz.nip30CustomEmoji.selection.EmojiPackSelectionEvent import com.vitorpamplona.quartz.nip30CustomEmoji.taggedEmojis diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/blockedRelays/BlockedRelayListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/blockedRelays/BlockedRelayListState.kt index 965e58bfc5..80c87c435d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/blockedRelays/BlockedRelayListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/blockedRelays/BlockedRelayListState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model.nip51Lists.blockedRelays -import android.util.Log import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note @@ -29,6 +28,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip51Lists.relayLists.BlockedRelayListEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/geohashLists/GeohashListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/geohashLists/GeohashListState.kt index 2bebd30948..1e747c0919 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/geohashLists/GeohashListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/geohashLists/GeohashListState.kt @@ -20,13 +20,13 @@ */ package com.vitorpamplona.amethyst.model.nip51Lists.geohashLists -import android.util.Log import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.NoteState import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip51Lists.geohashList.GeohashListEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/hashtagLists/HashtagListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/hashtagLists/HashtagListState.kt index 73e5906d8c..16f00e03d5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/hashtagLists/HashtagListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/hashtagLists/HashtagListState.kt @@ -20,13 +20,13 @@ */ package com.vitorpamplona.amethyst.model.nip51Lists.hashtagLists -import android.util.Log import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.NoteState import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip51Lists.hashtagList.HashtagListEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/muteList/MuteListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/muteList/MuteListState.kt index f78ba1f2ce..2b8f7e7bf4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/muteList/MuteListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/muteList/MuteListState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model.nip51Lists.muteList -import android.util.Log import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note @@ -30,6 +29,7 @@ import com.vitorpamplona.quartz.nip51Lists.muteList.MuteListEvent import com.vitorpamplona.quartz.nip51Lists.muteList.tags.MuteTag import com.vitorpamplona.quartz.nip51Lists.muteList.tags.UserTag import com.vitorpamplona.quartz.nip51Lists.muteList.tags.WordTag +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/searchRelays/SearchRelayListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/searchRelays/SearchRelayListState.kt index 590c409d4c..a92fceda0d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/searchRelays/SearchRelayListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/searchRelays/SearchRelayListState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model.nip51Lists.searchRelays -import android.util.Log import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.DefaultSearchRelayList import com.vitorpamplona.amethyst.model.LocalCache @@ -29,6 +28,7 @@ import com.vitorpamplona.amethyst.model.NoteState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip50Search.SearchRelayListEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/trustedRelays/TrustedRelayListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/trustedRelays/TrustedRelayListState.kt index 41aff1c06d..eabd779935 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/trustedRelays/TrustedRelayListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/trustedRelays/TrustedRelayListState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model.nip51Lists.trustedRelays -import android.util.Log import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note @@ -28,6 +27,7 @@ import com.vitorpamplona.amethyst.model.NoteState import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip51Lists.relayLists.TrustedRelayListEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip53LiveActivities/LiveActivitiesChannel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip53LiveActivities/LiveActivitiesChannel.kt index 34805ebfd9..312fd1e45e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip53LiveActivities/LiveActivitiesChannel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip53LiveActivities/LiveActivitiesChannel.kt @@ -25,8 +25,8 @@ import com.vitorpamplona.amethyst.model.Channel import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.note.toShortDisplay -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.core.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip19Bech32.entities.NAddress import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip65RelayList/Nip65RelayListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip65RelayList/Nip65RelayListState.kt index 8773f12cd4..b1d85a4294 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip65RelayList/Nip65RelayListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip65RelayList/Nip65RelayListState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model.nip65RelayList -import android.util.Log import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.Constants import com.vitorpamplona.amethyst.model.LocalCache @@ -30,6 +29,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent import com.vitorpamplona.quartz.nip65RelayList.tags.AdvertisedRelayInfo +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip72Communities/CommunityListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip72Communities/CommunityListState.kt index 24052d6205..7f057593a5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip72Communities/CommunityListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip72Communities/CommunityListState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.model.nip72Communities -import android.util.Log import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.LocalCache @@ -30,6 +29,7 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent import com.vitorpamplona.quartz.nip72ModCommunities.follow.CommunityListEvent import com.vitorpamplona.quartz.nip72ModCommunities.follow.tags.CommunityTag +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip78AppSpecific/AppSpecificState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip78AppSpecific/AppSpecificState.kt index d44cface2b..936191085f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip78AppSpecific/AppSpecificState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip78AppSpecific/AppSpecificState.kt @@ -20,15 +20,14 @@ */ package com.vitorpamplona.amethyst.model.nip78AppSpecific -import android.util.Log -import com.fasterxml.jackson.module.kotlin.readValue import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.amethyst.model.AccountSyncedSettingsInternal import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.NoteState -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip78AppData.AppSpecificDataEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers @@ -58,7 +57,7 @@ class AppSpecificState( val toInternal = settings.syncedSettings.toInternal() return AppSpecificDataEvent.create( dTag = APP_SPECIFIC_DATA_D_TAG, - description = signer.nip44Encrypt(JsonMapper.mapper.writeValueAsString(toInternal), signer.pubKey), + description = signer.nip44Encrypt(JsonMapper.toJson(toInternal), signer.pubKey), otherTags = emptyArray(), signer = signer, ) @@ -73,7 +72,7 @@ class AppSpecificState( LocalCache.justConsumeMyOwnEvent(event) try { val decrypted = signer.decrypt(event.content, event.pubKey) - val syncedSettings = JsonMapper.mapper.readValue(decrypted) + val syncedSettings = JsonMapper.fromJson(decrypted) settings.syncedSettings.updateFrom(syncedSettings) } catch (e: Throwable) { if (e is CancellationException) throw e @@ -90,7 +89,7 @@ class AppSpecificState( (it.note.event as? AppSpecificDataEvent)?.let { val decrypted = signer.decrypt(it.content, it.pubKey) try { - val syncedSettings = JsonMapper.mapper.readValue(decrypted) + val syncedSettings = JsonMapper.fromJson(decrypted) settings.updateAppSpecificData(it, syncedSettings) } catch (e: Throwable) { if (e is CancellationException) throw e diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/observables/LatestByKindAndAuthor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/observables/LatestByKindAndAuthor.kt index d7d3831988..c8b43ab5d5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/observables/LatestByKindAndAuthor.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/observables/LatestByKindAndAuthor.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.model.observables import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/AccountPreferenceStores.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/AccountPreferenceStores.kt index d847670418..61ad896092 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/AccountPreferenceStores.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/AccountPreferenceStores.kt @@ -24,7 +24,7 @@ import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.PreferenceDataStoreFactory import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.stringPreferencesKey -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.utils.cache.LargeCache import java.io.File class AccountPreferenceStores( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/AccountSecretsEncryptedStores.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/AccountSecretsEncryptedStores.kt index fadcad0354..7fc94d785f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/AccountSecretsEncryptedStores.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/AccountSecretsEncryptedStores.kt @@ -24,7 +24,7 @@ import androidx.datastore.preferences.core.PreferenceDataStoreFactory import androidx.datastore.preferences.core.stringPreferencesKey import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip47WalletConnect.Nip47WalletConnect -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.utils.cache.LargeCache import kotlinx.coroutines.CoroutineScope import java.io.File diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/EncryptedDataStore.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/EncryptedDataStore.kt index f3fc628e5e..6c8daf2b28 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/EncryptedDataStore.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/EncryptedDataStore.kt @@ -29,16 +29,16 @@ import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.map import java.io.IOException -import java.util.Base64 +import kotlin.io.encoding.Base64 class EncryptedDataStore( private val store: DataStore, private val encryption: KeyStoreEncryption = KeyStoreEncryption(), private val scope: CoroutineScope, ) { - private fun decode(str: String): ByteArray = Base64.getDecoder().decode(str) + private fun decode(str: String): ByteArray = Base64.decode(str) - private fun encode(bytes: ByteArray): String = Base64.getEncoder().encodeToString(bytes) + private fun encode(bytes: ByteArray): String = Base64.encode(bytes) private fun encrypt(value: String): String = encode(encryption.encrypt(value.toByteArray())) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/TorSharedPreferences.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/TorSharedPreferences.kt index af7fdaa96e..0944a43605 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/TorSharedPreferences.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/TorSharedPreferences.kt @@ -21,16 +21,15 @@ package com.vitorpamplona.amethyst.model.preferences import android.content.Context -import android.util.Log import androidx.compose.runtime.Stable import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.intPreferencesKey import androidx.datastore.preferences.core.stringPreferencesKey -import com.vitorpamplona.amethyst.ui.actions.MediaSaverToDisk.save import com.vitorpamplona.amethyst.ui.tor.TorSettings import com.vitorpamplona.amethyst.ui.tor.TorSettingsFlow import com.vitorpamplona.amethyst.ui.tor.TorType +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/UISharedPreferences.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/UISharedPreferences.kt index c1c70ca533..d4c88552e9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/UISharedPreferences.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/UISharedPreferences.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.model.preferences import android.content.Context -import android.util.Log import androidx.appcompat.app.AppCompatDelegate import androidx.compose.runtime.Stable import androidx.core.os.LocaleListCompat @@ -39,6 +38,7 @@ import com.vitorpamplona.amethyst.model.ProfileGalleryType import com.vitorpamplona.amethyst.model.ThemeType import com.vitorpamplona.amethyst.model.UiSettings import com.vitorpamplona.amethyst.model.UiSettingsFlow +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/privateChats/ChatroomList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/privateChats/ChatroomList.kt index 899495f67d..6a81dcf374 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/privateChats/ChatroomList.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/privateChats/ChatroomList.kt @@ -25,7 +25,7 @@ import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.utils.cache.LargeCache import kotlinx.collections.immutable.persistentSetOf class ChatroomList( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedServerListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedServerListState.kt index 578e912ed7..8c254d6601 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedServerListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedServerListState.kt @@ -25,6 +25,7 @@ import com.vitorpamplona.amethyst.model.nipB7Blossom.BlossomServerListState import com.vitorpamplona.amethyst.ui.actions.mediaServers.DEFAULT_MEDIA_SERVERS import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerName import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerType +import com.vitorpamplona.quartz.utils.Rfc3986 import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted @@ -33,7 +34,6 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn -import org.czeal.rfc3986.URIReference class MergedServerListState( val fileServers: FileStorageServerListState, @@ -42,7 +42,7 @@ class MergedServerListState( ) { fun host(url: String): String = try { - URIReference.parse(url).host.value + Rfc3986.host(url) } catch (e: Exception) { url } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByOutboxTopNavFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByOutboxTopNavFilter.kt index e917a47fa8..cd6675eca9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByOutboxTopNavFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByOutboxTopNavFilter.kt @@ -28,7 +28,7 @@ import com.vitorpamplona.amethyst.model.topNavFeeds.OutboxRelayLoader import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.isTaggedAddressableNotes +import com.vitorpamplona.quartz.nip01Core.tags.aTag.isTaggedAddressableNotes import com.vitorpamplona.quartz.nip01Core.tags.geohash.isTaggedGeoHashes import com.vitorpamplona.quartz.nip01Core.tags.hashtags.isTaggedHashes import com.vitorpamplona.quartz.nip22Comments.CommentEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByProxyTopNavFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByProxyTopNavFilter.kt index 83b7ca2a0d..ac271a3406 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByProxyTopNavFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByProxyTopNavFilter.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.amethyst.model.topNavFeeds.IFeedTopNavFilter import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.isTaggedAddressableNotes +import com.vitorpamplona.quartz.nip01Core.tags.aTag.isTaggedAddressableNotes import com.vitorpamplona.quartz.nip01Core.tags.geohash.isTaggedGeoHashes import com.vitorpamplona.quartz.nip01Core.tags.hashtags.isTaggedHashes import com.vitorpamplona.quartz.nip22Comments.CommentEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/allcommunities/AllCommunitiesTopNavFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/allcommunities/AllCommunitiesTopNavFilter.kt index 40debbe42d..57e2e34252 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/allcommunities/AllCommunitiesTopNavFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/allcommunities/AllCommunitiesTopNavFilter.kt @@ -27,7 +27,7 @@ import com.vitorpamplona.amethyst.model.topNavFeeds.IFeedTopNavFilter import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.isTaggedAddressableNotes +import com.vitorpamplona.quartz.nip01Core.tags.aTag.isTaggedAddressableNotes import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/community/SingleCommunityTopNavFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/community/SingleCommunityTopNavFilter.kt index 706b75fc99..8a4c3bb4d5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/community/SingleCommunityTopNavFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/community/SingleCommunityTopNavFilter.kt @@ -27,7 +27,7 @@ import com.vitorpamplona.amethyst.model.topNavFeeds.OutboxRelayLoader import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.isTaggedAddressableNote +import com.vitorpamplona.quartz.nip01Core.tags.aTag.isTaggedAddressableNote import com.vitorpamplona.quartz.nip22Comments.CommentEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent import kotlinx.coroutines.flow.Flow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/community/SingleCommunityTopNavPerRelayFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/community/SingleCommunityTopNavPerRelayFilter.kt index 508678a251..0c6ba06102 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/community/SingleCommunityTopNavPerRelayFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/community/SingleCommunityTopNavPerRelayFilter.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.community import androidx.compose.runtime.Immutable import com.vitorpamplona.amethyst.model.topNavFeeds.IFeedTopNavPerRelayFilter -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.core.Address @Immutable class SingleCommunityTopNavPerRelayFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt index ca94c68426..792efcb8af 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/CachedRichTextParser.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.service import android.util.LruCache import com.vitorpamplona.amethyst.commons.richtext.RichTextParser import com.vitorpamplona.amethyst.commons.richtext.RichTextViewerState -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists object CachedRichTextParser { private val richTextCache = LruCache(50) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/CoroutinesExt.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/CoroutinesExt.kt index 7475b91cee..e77a5cbe44 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/CoroutinesExt.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/CoroutinesExt.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.amethyst.service -import android.util.Log +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.delay diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/EmojiUtils.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/EmojiUtils.kt index 2f78457f33..543cd8fcea 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/EmojiUtils.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/EmojiUtils.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.commons.emojicoder.EmojiCoder -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists fun String.isUTF16Char(pos: Int): Boolean = Character.charCount(this.codePointAt(pos)) == 2 diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/OnlineCheck.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/OnlineCheck.kt index 1f406816c9..2a22f7e54d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/OnlineCheck.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/OnlineCheck.kt @@ -20,9 +20,9 @@ */ package com.vitorpamplona.amethyst.service -import android.util.Log import android.util.LruCache import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.RandomInstance import com.vitorpamplona.quartz.utils.TimeUtils import okhttp3.EventListener diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/connectivity/ConnectivityFlow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/connectivity/ConnectivityFlow.kt index d80d8faa97..8042d91249 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/connectivity/ConnectivityFlow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/connectivity/ConnectivityFlow.kt @@ -24,7 +24,7 @@ import android.content.Context import android.net.ConnectivityManager import android.net.Network import android.net.NetworkCapabilities -import android.util.Log +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.channels.awaitClose diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/eventCache/MemoryTrimmingService.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/eventCache/MemoryTrimmingService.kt index f41639f2b1..8e371a4231 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/eventCache/MemoryTrimmingService.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/eventCache/MemoryTrimmingService.kt @@ -20,11 +20,11 @@ */ package com.vitorpamplona.amethyst.service.eventCache -import android.util.Log import com.vitorpamplona.amethyst.AccountInfo import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.quartz.nip19Bech32.decodePublicKeyAsHexOrNull +import com.vitorpamplona.quartz.utils.Log import java.util.concurrent.atomic.AtomicBoolean class MemoryTrimmingService( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt index c814e07ea7..dd2779157d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.service.lnurl import android.content.Context -import android.util.Log import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.HttpStatusMessages @@ -29,6 +28,7 @@ import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.lightning.LnInvoiceUtil import com.vitorpamplona.quartz.lightning.Lud06 import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import okhttp3.OkHttpClient diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/CachedReversedGeoLocations.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/CachedReversedGeoLocations.kt index 44674d0b98..953fdf3195 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/CachedReversedGeoLocations.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/CachedReversedGeoLocations.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.service.location import android.content.Context import android.location.Geocoder import android.location.Location -import android.util.Log import android.util.LruCache +import com.vitorpamplona.quartz.utils.Log /** * Maintains a cache of geohashes and city,country pairs. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationFlow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationFlow.kt index de6d050271..bd5a3274f8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationFlow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationFlow.kt @@ -26,9 +26,9 @@ import android.location.Location import android.location.LocationListener import android.location.LocationManager import android.os.Looper -import android.util.Log import com.vitorpamplona.amethyst.service.location.LocationState.Companion.MIN_DISTANCE import com.vitorpamplona.amethyst.service.location.LocationState.Companion.MIN_TIME +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationState.kt index a9ae46535a..1446702b01 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationState.kt @@ -21,10 +21,10 @@ package com.vitorpamplona.amethyst.service.location import android.content.Context -import android.util.Log import com.fonfon.kgeohash.GeoHash import com.fonfon.kgeohash.toGeoHash import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeohashPrecision +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/ReverseGeolocation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/ReverseGeolocation.kt index 27e0c3120a..2072e87d25 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/ReverseGeolocation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/ReverseGeolocation.kt @@ -25,8 +25,8 @@ import android.location.Address import android.location.Geocoder import android.location.Location import android.os.Build -import android.util.Log import androidx.annotation.RequiresApi +import com.vitorpamplona.quartz.utils.Log import java.io.IOException class ReverseGeolocation { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/logging/ChoreographerHelper.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/logging/ChoreographerHelper.kt index 2acbb3119b..940a33de9b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/logging/ChoreographerHelper.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/logging/ChoreographerHelper.kt @@ -20,8 +20,8 @@ */ package com.vitorpamplona.amethyst.service.logging -import android.util.Log import android.view.Choreographer +import com.vitorpamplona.quartz.utils.Log object ChoreographerHelper { var lastFrameTimeNanos: Long = 0 diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/logging/LogMonitor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/logging/LogMonitor.kt index 1d35148f72..e7ea8821c2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/logging/LogMonitor.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/logging/LogMonitor.kt @@ -24,8 +24,8 @@ import android.annotation.SuppressLint import android.os.Handler import android.os.HandlerThread import android.os.Looper -import android.util.Log import android.util.Printer +import com.vitorpamplona.quartz.utils.Log import java.text.SimpleDateFormat import java.util.concurrent.atomic.AtomicBoolean diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt index 3b0727d02e..ba1949d02e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt @@ -22,14 +22,12 @@ package com.vitorpamplona.amethyst.service.notifications import android.app.NotificationManager import android.content.Context -import android.util.Log import androidx.core.content.ContextCompat import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache -import com.vitorpamplona.amethyst.model.LocalCache.chatroomList import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendDMNotification import com.vitorpamplona.amethyst.service.notifications.NotificationUtils.sendZapNotification @@ -49,6 +47,7 @@ import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import java.math.BigDecimal import kotlin.coroutines.cancellation.CancellationException diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/PokeyReceiver.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/PokeyReceiver.kt index 36b457cd5a..b6f3a2cd2c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/PokeyReceiver.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/PokeyReceiver.kt @@ -26,8 +26,8 @@ import android.content.Context.RECEIVER_EXPORTED import android.content.Intent import android.content.IntentFilter import android.os.Build -import android.util.Log import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt index 15f0513053..1203cdd9a9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.service.notifications -import android.util.Log import com.vitorpamplona.amethyst.AccountInfo import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.BuildConfig @@ -29,6 +28,7 @@ import com.vitorpamplona.amethyst.isDebug import com.vitorpamplona.amethyst.model.AccountSettings import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip42RelayAuth.RelayAuthEvent +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.mapNotNullAsync import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/EncryptedBlobInterceptor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/EncryptedBlobInterceptor.kt index bd71c92857..a10990720b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/EncryptedBlobInterceptor.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/EncryptedBlobInterceptor.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.amethyst.service.okhttp -import com.vitorpamplona.quartz.nip17Dm.files.encryption.AESGCM +import com.vitorpamplona.quartz.utils.ciphers.AESGCM import okhttp3.Interceptor import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.Response diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/EncryptionKeyCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/EncryptionKeyCache.kt index 5d31a668f3..20e2e43de7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/EncryptionKeyCache.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/EncryptionKeyCache.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.service.okhttp import android.util.LruCache -import com.vitorpamplona.quartz.nip17Dm.files.encryption.NostrCipher +import com.vitorpamplona.quartz.utils.ciphers.NostrCipher /** * Neigther ExoPlayer, nor Coil support passing key and nonce to the Interceptor via diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/LoggingInterceptor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/LoggingInterceptor.kt index e64baa7088..42fca1995e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/LoggingInterceptor.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/LoggingInterceptor.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.amethyst.service.okhttp -import android.util.Log +import com.vitorpamplona.quartz.utils.Log import okhttp3.Interceptor import okhttp3.Request import okhttp3.Response diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/OkHttpClientFactory.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/OkHttpClientFactory.kt index ec055e4487..8e6e1267e0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/OkHttpClientFactory.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/OkHttpClientFactory.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.service.okhttp import android.os.Build -import android.util.Log +import com.vitorpamplona.quartz.utils.Log import okhttp3.Dispatcher import okhttp3.OkHttpClient import java.net.InetSocketAddress diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/GetVideoController.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/GetVideoController.kt index e929a44c54..e35a1ecf01 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/GetVideoController.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/GetVideoController.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.service.playback.composable -import android.util.Log import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.remember @@ -33,6 +32,7 @@ import androidx.media3.common.Player import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.LoadedMediaItem import com.vitorpamplona.amethyst.service.playback.pip.BackgroundMedia import com.vitorpamplona.amethyst.service.playback.service.PlaybackServiceClient +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.util.concurrent.atomic.AtomicBoolean diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/MediaControllerState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/MediaControllerState.kt index 8316c56204..93cdc5b889 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/MediaControllerState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/MediaControllerState.kt @@ -25,12 +25,14 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.mutableStateOf import androidx.media3.session.MediaController -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) @Stable class MediaControllerState( // each composable has an ID. - val id: String = UUID.randomUUID().toString(), + val id: String = Uuid.random().toString(), // This is filled after the controller returns from this class var controller: MediaController? = null, // this set's the stage to keep playing on the background or not when the user leaves the screen diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/ExoPlayerPool.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/ExoPlayerPool.kt index 1feed28b3c..496b82e7b9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/ExoPlayerPool.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/ExoPlayerPool.kt @@ -21,10 +21,10 @@ package com.vitorpamplona.amethyst.service.playback.playerPool import android.content.Context -import android.util.Log import androidx.annotation.OptIn import androidx.media3.common.util.UnstableApi import androidx.media3.exoplayer.ExoPlayer +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/MediaSessionPool.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/MediaSessionPool.kt index 915f3ff378..3ec0bd726d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/MediaSessionPool.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/MediaSessionPool.kt @@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.service.playback.playerPool import android.app.PendingIntent import android.content.Context import android.content.Intent -import android.util.Log import android.util.LruCache import androidx.annotation.OptIn import androidx.core.net.toUri @@ -37,6 +36,7 @@ import androidx.media3.session.MediaSession import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture import com.vitorpamplona.amethyst.ui.MainActivity +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/service/PlaybackService.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/service/PlaybackService.kt index bb9a8474a5..71e7b84c29 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/service/PlaybackService.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/service/PlaybackService.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.service.playback.service -import android.util.Log import androidx.annotation.OptIn import androidx.media3.common.C import androidx.media3.common.Player @@ -34,6 +33,7 @@ import com.vitorpamplona.amethyst.service.playback.playerPool.ExoPlayerBuilder import com.vitorpamplona.amethyst.service.playback.playerPool.ExoPlayerPool import com.vitorpamplona.amethyst.service.playback.playerPool.MediaSessionPool import com.vitorpamplona.amethyst.service.playback.playerPool.SimultaneousPlaybackCalculator +import com.vitorpamplona.quartz.utils.Log import okhttp3.OkHttpClient class PlaybackService : MediaSessionService() { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/service/PlaybackServiceClient.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/service/PlaybackServiceClient.kt index 1bd5bf6dd6..7edf943d24 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/service/PlaybackServiceClient.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/service/PlaybackServiceClient.kt @@ -23,10 +23,10 @@ package com.vitorpamplona.amethyst.service.playback.service import android.content.ComponentName import android.content.Context import android.os.Bundle -import android.util.Log import androidx.media3.session.MediaController import androidx.media3.session.SessionToken import com.vitorpamplona.amethyst.service.playback.composable.MediaControllerState +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/RelayLogger.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/RelayLogger.kt index 2ff1505717..546c8b0f7d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/RelayLogger.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/RelayLogger.kt @@ -20,11 +20,11 @@ */ package com.vitorpamplona.amethyst.service.relayClient -import android.util.Log import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientListener import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient +import com.vitorpamplona.quartz.utils.Log /** * Listens to NostrClient's onNotify messages from the relay diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/RelayProxyClientConnector.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/RelayProxyClientConnector.kt index 56860511c8..277d9450d7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/RelayProxyClientConnector.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/RelayProxyClientConnector.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.service.relayClient -import android.util.Log import com.vitorpamplona.amethyst.model.torState.TorRelayEvaluation import com.vitorpamplona.amethyst.service.connectivity.ConnectivityManager import com.vitorpamplona.amethyst.service.connectivity.ConnectivityStatus @@ -28,6 +27,7 @@ import com.vitorpamplona.amethyst.service.okhttp.DualHttpClientManager import com.vitorpamplona.amethyst.ui.tor.TorManager import com.vitorpamplona.amethyst.ui.tor.TorServiceStatus import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/AuthCoordinator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/AuthCoordinator.kt index 4a3d7d9265..8cbeef9727 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/AuthCoordinator.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/AuthCoordinator.kt @@ -20,11 +20,11 @@ */ package com.vitorpamplona.amethyst.service.relayClient.authCommand.model -import android.util.Log import com.vitorpamplona.amethyst.isDebug import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.RelayAuthenticator +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope class ScreenAuthAccount( @@ -55,7 +55,7 @@ class AuthCoordinator( if (account == null) return if (isDebug) { - Log.d(this::class.simpleName, "Watch $account") + Log.d("AuthCoordinator", "Watch $account") } authWithAccounts.add(account) @@ -66,7 +66,7 @@ class AuthCoordinator( if (account == null) return if (isDebug) { - Log.d(this::class.simpleName, "Unwatch $account") + Log.d("AuthCoordinator", "Unwatch $account") } authWithAccounts.remove(account) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/eoseManagers/BaseEoseManager.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/eoseManagers/BaseEoseManager.kt index cfc55e4d83..70a0c54553 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/eoseManagers/BaseEoseManager.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/eoseManagers/BaseEoseManager.kt @@ -20,13 +20,13 @@ */ package com.vitorpamplona.amethyst.service.relayClient.eoseManagers -import android.util.Log import com.vitorpamplona.amethyst.isDebug import com.vitorpamplona.ammolite.relays.BundledUpdate import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.single.newSubId import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.SubscriptionController import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers abstract class BaseEoseManager( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/compose/NotifyRequestDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/compose/NotifyRequestDialog.kt index c87d634923..b61ab0ea85 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/compose/NotifyRequestDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/notifyCommand/compose/NotifyRequestDialog.kt @@ -46,7 +46,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size16dp import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList @Composable fun NotifyRequestDialog( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/FilterMissingAddressables.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/FilterMissingAddressables.kt index 89b222886c..e4f8384ec2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/FilterMissingAddressables.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/FilterMissingAddressables.kt @@ -23,10 +23,10 @@ package com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.loaders import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderQueryState +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.utils.mapOfSet fun potentialRelaysToFindAddress(note: AddressableNote): Set { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/FrameStat.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/FrameStat.kt index 745bc3f805..22ef301b77 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/FrameStat.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/FrameStat.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.amethyst.service.relayClient.speedLogger -import android.util.Log import com.vitorpamplona.amethyst.service.relayClient.speedLogger.RelaySpeedLogger.Companion.TAG import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.utils.Log +import com.vitorpamplona.quartz.utils.cache.LargeCache import java.util.concurrent.atomic.AtomicInteger import kotlin.concurrent.timer diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/KindGroup.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/KindGroup.kt index b648047f30..c1583feb16 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/KindGroup.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/KindGroup.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.amethyst.service.relayClient.speedLogger import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.utils.cache.LargeCache import java.util.concurrent.atomic.AtomicInteger import kotlin.concurrent.atomics.ExperimentalAtomicApi diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/RelaySpeedLogger.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/RelaySpeedLogger.kt index 19b5821ccf..fc565f5394 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/RelaySpeedLogger.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/RelaySpeedLogger.kt @@ -20,11 +20,11 @@ */ package com.vitorpamplona.amethyst.service.relayClient.speedLogger -import android.util.Log import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientListener import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient +import com.vitorpamplona.quartz.utils.Log /** * Listens to NostrClient's onNotify messages from the relay diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechHelper.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechHelper.kt index cc0f365dd0..f006c59623 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechHelper.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechHelper.kt @@ -21,10 +21,10 @@ package com.vitorpamplona.amethyst.service.tts import android.content.Context -import android.util.Log import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleOwner +import com.vitorpamplona.quartz.utils.Log import java.lang.ref.WeakReference import java.util.Locale diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/EncryptFiles.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/EncryptFiles.kt index 1babc6c493..f79e60af79 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/EncryptFiles.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/EncryptFiles.kt @@ -24,7 +24,7 @@ import android.content.Context import android.net.Uri import androidx.core.net.toUri import com.vitorpamplona.quartz.nip01Core.core.toHexKey -import com.vitorpamplona.quartz.nip17Dm.files.encryption.NostrCipher +import com.vitorpamplona.quartz.utils.ciphers.NostrCipher import com.vitorpamplona.quartz.utils.sha256.sha256 import java.io.File diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/FileHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/FileHeader.kt index afb2e8d2b3..29d86b669a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/FileHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/FileHeader.kt @@ -24,11 +24,11 @@ import android.graphics.Bitmap import android.graphics.BitmapFactory import android.media.MediaDataSource import android.media.MediaMetadataRetriever -import android.util.Log import com.vitorpamplona.amethyst.commons.blurhash.toBlurhash import com.vitorpamplona.amethyst.service.images.BlurhashWrapper import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.sha256.sha256 import kotlinx.coroutines.CancellationException import okhttp3.OkHttpClient diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/MediaCompressor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/MediaCompressor.kt index 444b297914..9f5cfe255f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/MediaCompressor.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/MediaCompressor.kt @@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.service.uploads import android.content.Context import android.graphics.Bitmap import android.net.Uri -import android.util.Log import androidx.core.net.toUri import androidx.media3.common.MimeTypes import com.abedelazizshe.lightcompressorlibrary.CompressionListener @@ -33,14 +32,16 @@ import com.abedelazizshe.lightcompressorlibrary.config.AppSpecificStorageConfigu import com.abedelazizshe.lightcompressorlibrary.config.Configuration import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.ui.components.util.MediaCompressorFileUtils +import com.vitorpamplona.quartz.utils.Log import id.zelory.compressor.Compressor import id.zelory.compressor.constraint.default import kotlinx.coroutines.CancellationException import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withTimeoutOrNull import java.io.File -import java.util.UUID import kotlin.coroutines.resume +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid class MediaCompressorResult( val uri: Uri, @@ -75,6 +76,7 @@ class MediaCompressor { } } + @OptIn(ExperimentalUuidApi::class) private suspend fun compressVideo( uri: Uri, contentType: String?, @@ -114,7 +116,7 @@ class MediaCompressor { Configuration( quality = videoQuality, // => required name - videoNames = listOf(UUID.randomUUID().toString()), + videoNames = listOf(Uuid.random().toString()), ), listener = object : CompressionListener { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/MultiOrchestrator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/MultiOrchestrator.kt index 424a3cd82f..45d8269e24 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/MultiOrchestrator.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/MultiOrchestrator.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerName import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMediaProcessing -import com.vitorpamplona.quartz.nip17Dm.files.encryption.NostrCipher +import com.vitorpamplona.quartz.utils.ciphers.NostrCipher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.joinAll diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/UploadOrchestrator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/UploadOrchestrator.kt index 94d4287aa3..dd011f74f2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/UploadOrchestrator.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/UploadOrchestrator.kt @@ -31,7 +31,7 @@ import com.vitorpamplona.amethyst.service.uploads.nip96.Nip96Uploader import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerName import com.vitorpamplona.amethyst.ui.actions.mediaServers.ServerType import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions -import com.vitorpamplona.quartz.nip17Dm.files.encryption.NostrCipher +import com.vitorpamplona.quartz.utils.ciphers.NostrCipher import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.map import okhttp3.OkHttpClient diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomUploader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomUploader.kt index f655507330..d97367448a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomUploader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/blossom/BlossomUploader.kt @@ -25,16 +25,16 @@ import android.content.Context import android.net.Uri import android.provider.OpenableColumns import android.webkit.MimeTypeMap -import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.service.HttpStatusMessages import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.service.uploads.MediaUploadResult import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nipB7Blossom.BlossomAuthorizationEvent +import com.vitorpamplona.quartz.nipB7Blossom.BlossomUploadResult import com.vitorpamplona.quartz.utils.RandomInstance import com.vitorpamplona.quartz.utils.sha256.sha256 import kotlinx.coroutines.Dispatchers @@ -170,7 +170,7 @@ class BlossomUploader { withContext(Dispatchers.IO) { if (response.isSuccessful) { response.body.use { body -> - parseResults(body.string()) + convertToMediaResult(parseResults(body.string())) } } else { val errorMessage = response.headers.get("X-Reason") @@ -188,6 +188,18 @@ class BlossomUploader { } } + fun convertToMediaResult(result: BlossomUploadResult): MediaUploadResult = + MediaUploadResult( + url = result.url, + type = result.type, + sha256 = result.sha256, + size = result.size, + uploaded = result.uploaded, + magnet = result.magnet, + infohash = result.infohash, + ipfs = result.ipfs, + ) + fun String.displayUrl() = this.removeSuffix("/").removePrefix("https://") suspend fun delete( @@ -231,8 +243,5 @@ class BlossomUploader { } } - private fun parseResults(body: String): MediaUploadResult { - val mapper = jacksonObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - return mapper.readValue(body, MediaUploadResult::class.java) - } + private fun parseResults(body: String): BlossomUploadResult = JsonMapper.fromJson(body) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/nip96/Nip96Uploader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/nip96/Nip96Uploader.kt index ca9814468b..1490c1d7d0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/nip96/Nip96Uploader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/nip96/Nip96Uploader.kt @@ -32,6 +32,7 @@ import com.vitorpamplona.amethyst.service.HttpStatusMessages import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.service.uploads.MediaUploadResult import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import com.vitorpamplona.quartz.nip36SensitiveContent.ContentWarningTag import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag import com.vitorpamplona.quartz.nip96FileStorage.actions.DeleteResult @@ -181,7 +182,7 @@ class Nip96Uploader { withContext(Dispatchers.IO) { if (response.isSuccessful) { response.body.use { body -> - val result = UploadResult.parse(body.string()) + val result = JsonMapper.fromJson(body.string()) if (!result.processingUrl.isNullOrBlank()) { waitProcessing(result, server, okHttpClient, onProgress) } else if (result.status == "success") { @@ -287,7 +288,7 @@ class Nip96Uploader { return client.newCall(request).executeAsync().use { response -> withContext(Dispatchers.IO) { if (response.isSuccessful) { - val result = DeleteResult.parse(response.body.string()) + val result = JsonMapper.fromJson(response.body.string()) result.status == "success" } else { val explanation = HttpStatusMessages.resourceIdFor(response.code) @@ -324,7 +325,7 @@ class Nip96Uploader { client.newCall(request).executeAsync().use { response -> withContext(Dispatchers.IO) { if (response.isSuccessful) { - currentResult = UploadResult.parse(response.body.string()) + currentResult = JsonMapper.fromJson(response.body.string()) } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/nip96/ServerInfoRetriever.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/nip96/ServerInfoRetriever.kt index 55cf8147f5..3520c41b03 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/nip96/ServerInfoRetriever.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/uploads/nip96/ServerInfoRetriever.kt @@ -20,9 +20,9 @@ */ package com.vitorpamplona.amethyst.service.uploads.nip96 -import android.util.Log import com.vitorpamplona.quartz.nip96FileStorage.info.ServerInfo import com.vitorpamplona.quartz.nip96FileStorage.info.ServerInfoParser +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index 2b8a9e1f4a..85527e818b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -22,13 +22,11 @@ package com.vitorpamplona.amethyst.ui import android.os.Build import android.os.Bundle -import android.util.Log import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.debugState @@ -51,6 +49,7 @@ import com.vitorpamplona.quartz.nip19Bech32.entities.NNote import com.vitorpamplona.quartz.nip19Bech32.entities.NProfile import com.vitorpamplona.quartz.nip19Bech32.entities.NPub import com.vitorpamplona.quartz.nip47WalletConnect.Nip47WalletConnect +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/MediaSaverToDisk.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/MediaSaverToDisk.kt index 8a02c884f5..b85db2ca2b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/MediaSaverToDisk.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/MediaSaverToDisk.kt @@ -27,12 +27,12 @@ import android.media.MediaScannerConnection import android.os.Build import android.os.Environment import android.provider.MediaStore -import android.util.Log import android.webkit.MimeTypeMap import androidx.annotation.RequiresApi import androidx.core.net.toFile import androidx.core.net.toUri import com.vitorpamplona.amethyst.ui.actions.MediaSaverToDisk.PICTURES_SUBDIRECTORY +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -44,7 +44,8 @@ import okio.buffer import okio.sink import okio.source import java.io.File -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid object MediaSaverToDisk { suspend fun saveDownloadingIfNeeded( @@ -142,6 +143,7 @@ object MediaSaverToDisk { MimeTypeMap.getSingleton().getMimeTypeFromExtension(it).orEmpty() } + @OptIn(ExperimentalUuidApi::class) fun save( localFile: File, mimeType: String?, @@ -156,14 +158,14 @@ object MediaSaverToDisk { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { saveContentQ( - displayName = UUID.randomUUID().toString(), + displayName = Uuid.random().toString(), contentType = mimeType ?: "", contentSource = buffer, contentResolver = context.contentResolver, ) } else { saveContentDefault( - fileName = "${UUID.randomUUID()}.$extension", + fileName = "${Uuid.random()}.$extension", contentSource = buffer, context = context, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMessageTagger.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMessageTagger.kt index 9ac7dfe6bf..40ce38396a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMessageTagger.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMessageTagger.kt @@ -24,9 +24,9 @@ import androidx.compose.runtime.Immutable import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.crypto.Nip01 -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip19Bech32.Nip19Parser import com.vitorpamplona.quartz.nip19Bech32.bech32.Bech32 import com.vitorpamplona.quartz.nip19Bech32.bech32.bechToBytes diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomServersViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomServersViewModel.kt index 6eab5aadb2..4c223bf1be 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomServersViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/BlossomServersViewModel.kt @@ -20,16 +20,16 @@ */ package com.vitorpamplona.amethyst.ui.actions.mediaServers -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.quartz.utils.Log +import com.vitorpamplona.quartz.utils.Rfc3986 import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import org.czeal.rfc3986.URIReference class BlossomServersViewModel : ViewModel() { lateinit var account: Account @@ -50,7 +50,7 @@ class BlossomServersViewModel : ViewModel() { obtainedFileServers.mapNotNull { serverUrl -> try { ServerName( - URIReference.parse(serverUrl).host.value, + Rfc3986.host(serverUrl), serverUrl, ServerType.Blossom, ) @@ -71,13 +71,13 @@ class BlossomServersViewModel : ViewModel() { fun addServer(serverUrl: String) { val normalizedUrl = try { - URIReference.parse(serverUrl.trim()).normalize().toString() + Rfc3986.normalize(serverUrl.trim()) } catch (e: Exception) { serverUrl } val serverNameReference = try { - URIReference.parse(normalizedUrl).host.value + Rfc3986.host(normalizedUrl) } catch (e: Exception) { normalizedUrl } @@ -102,7 +102,7 @@ class BlossomServersViewModel : ViewModel() { serverUrl: String, ) { viewModelScope.launch { - val serverName = if (name.isNotBlank()) name else URIReference.parse(serverUrl).host.value + val serverName = if (name.isNotBlank()) name else Rfc3986.host(serverUrl) _fileServers.update { it.minus( ServerName(serverName, serverUrl, ServerType.Blossom), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/MediaServerEditField.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/MediaServerEditField.kt index 0d0e67c3ad..b81b3a6b6d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/MediaServerEditField.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/MediaServerEditField.kt @@ -40,7 +40,7 @@ import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.placeholderText -import com.vitorpamplona.quartz.nip96FileStorage.HttpUrlFormatter +import com.vitorpamplona.quartz.nip01Core.tags.references.HttpUrlFormatter @Composable fun MediaServerEditField( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/NIP96ServersViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/NIP96ServersViewModel.kt index 0d8c32b19a..641b7be152 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/NIP96ServersViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/NIP96ServersViewModel.kt @@ -20,16 +20,16 @@ */ package com.vitorpamplona.amethyst.ui.actions.mediaServers -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.quartz.utils.Log +import com.vitorpamplona.quartz.utils.Rfc3986 import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import org.czeal.rfc3986.URIReference class NIP96ServersViewModel : ViewModel() { lateinit var account: Account @@ -50,7 +50,7 @@ class NIP96ServersViewModel : ViewModel() { obtainedFileServers.mapNotNull { serverUrl -> try { ServerName( - URIReference.parse(serverUrl).host.value, + Rfc3986.host(serverUrl), serverUrl, ServerType.NIP96, ) @@ -71,13 +71,13 @@ class NIP96ServersViewModel : ViewModel() { fun addServer(serverUrl: String) { val normalizedUrl = try { - URIReference.parse(serverUrl.trim()).normalize().toString() + Rfc3986.normalize(serverUrl.trim()) } catch (e: Exception) { serverUrl } val serverNameReference = try { - URIReference.parse(normalizedUrl).host.value + Rfc3986.host(normalizedUrl) } catch (e: Exception) { normalizedUrl } @@ -97,7 +97,7 @@ class NIP96ServersViewModel : ViewModel() { serverUrl: String, ) { viewModelScope.launch { - val serverName = if (name.isNotBlank()) name else URIReference.parse(serverUrl).host.value + val serverName = if (name.isNotBlank()) name else Rfc3986.host(serverUrl) _fileServers.update { it.minus( ServerName(serverName, serverUrl, ServerType.NIP96), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/ServerName.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/ServerName.kt index a7698c60a2..2b499f6062 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/ServerName.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/mediaServers/ServerName.kt @@ -20,6 +20,9 @@ */ package com.vitorpamplona.amethyst.ui.actions.mediaServers +import kotlinx.serialization.Serializable + +@Serializable data class ServerName( val name: String, val baseUrl: String, @@ -37,7 +40,7 @@ val DEFAULT_MEDIA_SERVERS: List = ServerName("Nostr.Build", "https://nostr.build", ServerType.NIP96), ServerName("NostrCheck.me (NIP-96)", "https://nostrcheck.me", ServerType.NIP96), ServerName("Sovbit", "https://files.sovbit.host", ServerType.NIP96), - ServerName("Void.cat", "https://void.cat", ServerType.NIP96), + // ServerName("Void.cat", "https://void.cat", ServerType.NIP96), ServerName("Satellite (Paid)", "https://cdn.satellite.earth", ServerType.Blossom), ServerName("NostrCheck.me (Blossom)", "https://cdn.nostrcheck.me", ServerType.Blossom), ServerName("Nostr.Download", "https://nostr.download", ServerType.Blossom), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/ShowImageUploadItem.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/ShowImageUploadItem.kt index 10f5382901..f063cbd058 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/ShowImageUploadItem.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/uploads/ShowImageUploadItem.kt @@ -25,7 +25,6 @@ import android.graphics.Bitmap import android.media.MediaMetadataRetriever import android.net.Uri import android.os.Build -import android.util.Log import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -70,6 +69,7 @@ import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.ui.theme.Size40Modifier import com.vitorpamplona.amethyst.ui.theme.Size55Modifier +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt index 1e304ab32e..2c901159ee 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt @@ -63,10 +63,10 @@ import com.vitorpamplona.amethyst.ui.navigation.routes.Route import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.ui.note.njumpLink import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists import com.vitorpamplona.quartz.nip19Bech32.Nip19Parser import com.vitorpamplona.quartz.nip19Bech32.entities.NAddress import com.vitorpamplona.quartz.nip19Bech32.entities.NEmbed diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt index 6d6b55a9c6..9b1f191f3b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt @@ -48,7 +48,7 @@ import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonPadding import com.vitorpamplona.amethyst.ui.theme.StdTopPadding -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists object ShowFullTextCache { val cache = LruCache(10) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt index 8a6d84cac7..0d2b191969 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt @@ -104,8 +104,8 @@ import com.vitorpamplona.amethyst.ui.theme.HalfVertPadding import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.ui.theme.inlinePlaceholder import com.vitorpamplona.amethyst.ui.theme.innerPostModifier -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ShareHelper.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ShareHelper.kt index 279308bfc8..c88f6d6fe2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ShareHelper.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ShareHelper.kt @@ -22,9 +22,9 @@ package com.vitorpamplona.amethyst.ui.components import android.content.Context import android.net.Uri -import android.util.Log import androidx.core.content.FileProvider import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.io.File diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index ac6c659607..222898aa88 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.components import android.content.Context import android.content.Intent -import android.util.Log import android.widget.Toast import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibilityScope @@ -105,6 +104,7 @@ import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip19Bech32.Nip19Parser import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.sha256.sha256 import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/RenderContentAsMarkdown.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/RenderContentAsMarkdown.kt index a70b427f20..4be4fcb404 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/RenderContentAsMarkdown.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/markdown/RenderContentAsMarkdown.kt @@ -49,9 +49,9 @@ import com.vitorpamplona.amethyst.ui.theme.MarkdownTextStyle import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonRow import com.vitorpamplona.amethyst.ui.theme.markdownStyle import com.vitorpamplona.amethyst.ui.uriToRoute +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent import com.vitorpamplona.quartz.nip92IMeta.imetasByUrl import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/util/MediaCompressorFileUtils.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/util/MediaCompressorFileUtils.kt index 325a327306..72b9286f1d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/util/MediaCompressorFileUtils.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/util/MediaCompressorFileUtils.kt @@ -27,16 +27,18 @@ import java.io.File import java.io.FileOutputStream import java.io.InputStream import java.io.OutputStream -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid object MediaCompressorFileUtils { + @OptIn(ExperimentalUuidApi::class) fun from( uri: Uri, context: Context, ): File { val extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(context.contentResolver.getType(uri)) ?: "" val suffix = if (extension.isNotEmpty()) ".$extension" else "" - val tempFile = File.createTempFile(UUID.randomUUID().toString(), suffix) + val tempFile = File.createTempFile(Uuid.random().toString(), suffix) context.contentResolver.openInputStream(uri)?.use { inputStream -> FileOutputStream(tempFile).use { outputStream -> diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/FilterByListParams.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/FilterByListParams.kt index 7ecbe13393..accd8d6853 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/FilterByListParams.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/dal/FilterByListParams.kt @@ -25,10 +25,10 @@ import com.vitorpamplona.amethyst.model.topNavFeeds.IFeedTopNavFilter import com.vitorpamplona.amethyst.model.topNavFeeds.global.GlobalTopNavFilter import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.muted.MutedAuthorsByOutboxTopNavFilter import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.muted.MutedAuthorsByProxyTopNavFilter +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip51Lists.muteList.MuteListEvent import com.vitorpamplona.quartz.nip51Lists.peopleList.PeopleListEvent import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/ChannelFeedContentState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/ChannelFeedContentState.kt index 26d465a95c..af7b4b4192 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/ChannelFeedContentState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/ChannelFeedContentState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.feeds -import android.util.Log import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.mutableStateOf @@ -31,6 +30,7 @@ import com.vitorpamplona.amethyst.ui.dal.AdditiveComplexFeedFilter import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists import com.vitorpamplona.ammolite.relays.BundledInsert import com.vitorpamplona.ammolite.relays.BundledUpdate +import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt index 385f538a01..908a5c1607 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt @@ -95,8 +95,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.VideoScreen import com.vitorpamplona.amethyst.ui.screen.loggedOff.AddAccountDialog import com.vitorpamplona.amethyst.ui.uriToRoute import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip19Bech32.Nip19Parser import kotlinx.coroutines.delay import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/DrawerContent.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/DrawerContent.kt index 29a0943cac..2ea414187e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/DrawerContent.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/DrawerContent.kt @@ -120,10 +120,10 @@ import com.vitorpamplona.amethyst.ui.theme.bannerModifier import com.vitorpamplona.amethyst.ui.theme.drawerSpacing import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.profileContentHeaderModifier +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayPool -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists @Composable fun DrawerContent( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Loaders.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Loaders.kt index 6ada3dda74..1328401a7a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Loaders.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/Loaders.kt @@ -44,7 +44,7 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUse import com.vitorpamplona.amethyst.ui.components.GenericLoadable import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.core.Address import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.suspendCancellableCoroutine diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt index ae6e09a158..3ee67c5c7b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt @@ -96,7 +96,7 @@ import com.vitorpamplona.amethyst.ui.theme.WidthAuthorPictureModifierWithPadding import com.vitorpamplona.amethyst.ui.theme.bitcoinColor import com.vitorpamplona.amethyst.ui.theme.overPictureBackground import com.vitorpamplona.amethyst.ui.theme.profile35dpModifier -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList import com.vitorpamplona.quartz.nip30CustomEmoji.CustomEmoji import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt index e55fbd8800..238f52c3b6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt @@ -76,9 +76,9 @@ import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.lessImportantLink import com.vitorpamplona.amethyst.ui.theme.nip05 import com.vitorpamplona.amethyst.ui.theme.placeholderText +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.metadata.UserMetadata -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address -import com.vitorpamplona.quartz.nip01Core.tags.addressables.firstTaggedAddress +import com.vitorpamplona.quartz.nip01Core.tags.aTag.firstTaggedAddress import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.events.firstTaggedEvent import com.vitorpamplona.quartz.nip38UserStatus.StatusEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt index f7473724af..cf5d6d14ea 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt @@ -97,9 +97,9 @@ import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.ripple24dp import com.vitorpamplona.quartz.experimental.zapPolls.PollNoteEvent -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt index 16060c726f..c2ae950559 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UpdateReactionTypeDialog.kt @@ -90,7 +90,7 @@ import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.placeholderText -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip30CustomEmoji.CustomEmoji import com.vitorpamplona.quartz.nip30CustomEmoji.EmojiUrlTag import com.vitorpamplona.quartz.nip30CustomEmoji.selection.EmojiPackSelectionEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt index e403f47965..0c8a4a4ef8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UsernameDisplay.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.ui.note import android.content.Context -import android.util.Log import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -45,7 +44,8 @@ import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.StdButtonSizeModifier import com.vitorpamplona.amethyst.ui.theme.placeholderText -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists +import com.vitorpamplona.quartz.utils.Log @Composable fun NoteUsernameDisplay( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/emojiSuggestions/WatchAndLoadMyEmojiList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/emojiSuggestions/WatchAndLoadMyEmojiList.kt index 35209d6e8c..eb16733a7a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/emojiSuggestions/WatchAndLoadMyEmojiList.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/emojiSuggestions/WatchAndLoadMyEmojiList.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFind import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEventAndMap import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.quartz.nip01Core.tags.addressables.taggedAddresses +import com.vitorpamplona.quartz.nip01Core.tags.aTag.taggedAddresses import com.vitorpamplona.quartz.nip30CustomEmoji.selection.EmojiPackSelectionEvent import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt index d33c8a1211..2ccccdf268 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayCommunity.kt @@ -34,7 +34,7 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.Route import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.HalfStartPadding -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip72ModCommunities.communityAddress @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt index 0e69f62952..8cd1da73b1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt @@ -35,8 +35,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.HalfTopPadding import com.vitorpamplona.amethyst.ui.theme.lessImportantLink import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists @Composable fun DisplayUncitedHashtags( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt index 71e3ab8bc2..da226558ec 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AppDefinition.kt @@ -69,8 +69,8 @@ import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size16Modifier import com.vitorpamplona.amethyst.ui.theme.Size35dp import com.vitorpamplona.amethyst.ui.theme.placeholderText -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppMetadata import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt index 718b6e378a..cb37c17cc2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt @@ -56,8 +56,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.experimental.audio.header.AudioHeaderEvent import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent import com.vitorpamplona.quartz.experimental.audio.track.tags.ParticipantTag +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists import com.vitorpamplona.quartz.nip14Subject.subject @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt index b6a8579059..1154317846 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/CommunityHeader.kt @@ -95,9 +95,9 @@ import com.vitorpamplona.amethyst.ui.theme.Size35dp import com.vitorpamplona.amethyst.ui.theme.Size5dp import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.innerPostModifier +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent import com.vitorpamplona.quartz.nip72ModCommunities.definition.tags.ModeratorTag import kotlinx.collections.immutable.ImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt index 844d9e47cb..0e03df161f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt @@ -57,7 +57,7 @@ import com.vitorpamplona.amethyst.ui.note.elements.RemoveButton import com.vitorpamplona.amethyst.ui.note.getGradient import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.Size35Modifier -import com.vitorpamplona.quartz.nip01Core.tags.addressables.isTaggedAddressableNote +import com.vitorpamplona.quartz.nip01Core.tags.aTag.isTaggedAddressableNote import com.vitorpamplona.quartz.nip30CustomEmoji.EmojiUrlTag import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent import com.vitorpamplona.quartz.nip30CustomEmoji.taggedEmojis diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt index bf5aad6cb9..52ba582547 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Git.kt @@ -61,9 +61,9 @@ import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.replyModifier import com.vitorpamplona.amethyst.ui.theme.subtleBorder +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip14Subject.subject import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt index d25ae7476a..4f0e833b59 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.ui.note.types import android.net.Uri -import android.util.Log import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow @@ -52,12 +51,13 @@ import com.vitorpamplona.amethyst.ui.components.measureSpaceWidth import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.quartz.nip01Core.core.Address +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList import com.vitorpamplona.quartz.nip01Core.core.firstTagValueFor -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip01Core.tags.events.ETag -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent import com.vitorpamplona.quartz.nip84Highlights.HighlightEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.net.URL diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt index cf124de8f5..08afdcf5bb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/InteractiveStory.kt @@ -48,8 +48,8 @@ import com.vitorpamplona.amethyst.ui.note.LoadAddressableNote import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.experimental.interactiveStories.InteractiveStoryBaseEvent import com.vitorpamplona.quartz.experimental.interactiveStories.InteractiveStoryReadingStateEvent +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList @Composable fun RenderInteractiveStory( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt index 66c9bb98ad..734c2fde26 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/NIP90ContentDiscoveryResponse.kt @@ -32,9 +32,9 @@ import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists import com.vitorpamplona.quartz.nip90Dvms.NIP90ContentDiscoveryResponseEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PictureDisplay.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PictureDisplay.kt index 67ad354aa7..6b0f27e35e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PictureDisplay.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PictureDisplay.kt @@ -44,7 +44,7 @@ import com.vitorpamplona.amethyst.ui.components.ZoomableContentView import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList import com.vitorpamplona.quartz.nip68Picture.PictureEvent import kotlinx.collections.immutable.toImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt index 39eafb0c38..afc871c086 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PinList.kt @@ -53,7 +53,7 @@ import com.vitorpamplona.amethyst.ui.note.PinIcon import com.vitorpamplona.amethyst.ui.note.getGradient import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.Size15Modifier -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList import com.vitorpamplona.quartz.nip51Lists.PinListEvent @OptIn(ExperimentalLayoutApi::class) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt index 089b67877b..bf0a07f688 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt @@ -44,10 +44,10 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.experimental.zapPolls.PollNoteEvent +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags import com.vitorpamplona.quartz.nip01Core.tags.people.hasAnyTaggedUser -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt index a17db97998..583a22ab7a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PrivateMessage.kt @@ -48,9 +48,9 @@ import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.replyModifier +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists import com.vitorpamplona.quartz.nip04Dm.messages.PrivateDmEvent import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable import com.vitorpamplona.quartz.nip19Bech32.toNpub diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt index 0dcccc8a49..78f0fedd15 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt @@ -44,8 +44,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.HalfHalfTopPadding import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.experimental.publicMessages.PublicMessageEvent +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists @Composable fun RenderPublicMessage( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt index bbc44aab40..c2edd7debf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Report.kt @@ -34,7 +34,7 @@ import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.replyModifier -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList import com.vitorpamplona.quartz.nip56Reports.ReportEvent import com.vitorpamplona.quartz.nip56Reports.ReportType diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt index e1f60d664a..8432deaa27 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Text.kt @@ -45,10 +45,10 @@ import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.placeholderText +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags import com.vitorpamplona.quartz.nip01Core.tags.people.hasAnyTaggedUser -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip14Subject.subject diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt index fa80c2a343..efa188f017 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TextModification.kt @@ -61,7 +61,7 @@ import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.imageModifier import com.vitorpamplona.amethyst.ui.theme.innerPostModifier import com.vitorpamplona.quartz.experimental.edits.TextNoteModificationEvent -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList import kotlinx.collections.immutable.persistentListOf @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Torrent.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Torrent.kt index 81a196ec63..53c24df271 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Torrent.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Torrent.kt @@ -179,7 +179,7 @@ fun DisplayFileList( files: ImmutableList, name: String, description: String?, - link: () -> String, + link: () -> String?, backgroundColor: MutableState, accountViewModel: AccountViewModel, nav: INav, @@ -215,10 +215,14 @@ fun DisplayFileList( IconButton( onClick = { try { - val intent = Intent(Intent.ACTION_VIEW, link().toUri()) - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK - - context.startActivity(intent) + val linkStr = link() + if (linkStr != null) { + val intent = Intent(Intent.ACTION_VIEW, linkStr.toUri()) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + context.startActivity(intent) + } else { + accountViewModel.toastManager.toast(R.string.torrent_failure, R.string.torrent_no_info) + } } catch (e: Exception) { if (e is CancellationException) throw e accountViewModel.toastManager.toast(R.string.torrent_failure, R.string.torrent_no_apps) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt index f49d1b10cf..b8c26a7bed 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Video.kt @@ -59,10 +59,10 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size5dp import com.vitorpamplona.amethyst.ui.theme.imageModifier +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip71Video.VideoEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt index d5a0532408..2e725c53e6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen -import android.util.Log import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Arrangement @@ -39,6 +38,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.screen.loggedIn.LoggedInPage import com.vitorpamplona.amethyst.ui.screen.loggedOff.LoginOrSignupScreen import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.quartz.utils.Log @Composable fun AccountScreen(accountStateViewModel: AccountStateViewModel) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt index 573ec8c308..54ca707d70 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen -import android.util.Log import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -60,6 +59,7 @@ import com.vitorpamplona.quartz.nip49PrivKeyEnc.Nip49 import com.vitorpamplona.quartz.nip50Search.SearchRelayListEvent import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent import com.vitorpamplona.quartz.utils.Hex +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt index 62ad0b4d3a..4484f8bc8e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen -import android.util.Log import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -29,6 +28,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.dal.FeedFilter import com.vitorpamplona.amethyst.ui.feeds.FeedContentState import com.vitorpamplona.amethyst.ui.feeds.InvalidatableContent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FollowListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FollowListState.kt index 5ccdd707d1..13ab5552e1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FollowListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FollowListState.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.ui.screen import android.content.Context -import android.util.Log import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.R @@ -57,6 +56,7 @@ import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent import com.vitorpamplona.quartz.nip72ModCommunities.approval.CommunityPostApprovalEvent import com.vitorpamplona.quartz.nip84Highlights.HighlightEvent import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt index 64d0813cba..34203a6dd9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedViewModel.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen -import android.util.Log import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.mutableStateOf @@ -33,6 +32,7 @@ import com.vitorpamplona.amethyst.ui.dal.FeedFilter import com.vitorpamplona.amethyst.ui.feeds.InvalidatableContent import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists import com.vitorpamplona.ammolite.relays.BundledUpdate +import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index 87f3ba2f6d..6ebaf6a048 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn import android.annotation.SuppressLint import android.content.Context import android.graphics.drawable.Drawable -import android.util.Log import android.util.LruCache import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable @@ -92,6 +91,7 @@ import com.vitorpamplona.amethyst.ui.tor.TorType import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId import com.vitorpamplona.quartz.experimental.interactiveStories.InteractiveStoryBaseEvent import com.vitorpamplona.quartz.experimental.interactiveStories.InteractiveStoryReadingStateEvent +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey @@ -102,10 +102,14 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.EmptyNostrClient import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip01Core.tags.people.PubKeyReferenceTag import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser -import com.vitorpamplona.quartz.nip03Timestamp.DefaultOtsResolverBuilder +import com.vitorpamplona.quartz.nip03Timestamp.OtsResolver +import com.vitorpamplona.quartz.nip03Timestamp.OtsResolverBuilder +import com.vitorpamplona.quartz.nip03Timestamp.ots.BitcoinExplorer +import com.vitorpamplona.quartz.nip03Timestamp.ots.BlockHeader +import com.vitorpamplona.quartz.nip03Timestamp.ots.RemoteCalendar +import com.vitorpamplona.quartz.nip03Timestamp.ots.Timestamp import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent import com.vitorpamplona.quartz.nip18Reposts.RepostEvent @@ -136,6 +140,7 @@ import com.vitorpamplona.quartz.nip90Dvms.NIP90ContentDiscoveryResponseEvent import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceEvent import com.vitorpamplona.quartz.utils.Hex +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.mapNotNullAsync import kotlinx.collections.immutable.ImmutableList @@ -1640,8 +1645,6 @@ var mockedCache: AccountViewModel? = null fun mockAccountViewModel(): AccountViewModel { mockedCache?.let { return it } - val otsResolver = DefaultOtsResolverBuilder() - val scope = rememberCoroutineScope() val uiState = @@ -1668,7 +1671,7 @@ fun mockAccountViewModel(): AccountViewModel { signer = NostrSignerInternal(keyPair), geolocationFlow = MutableStateFlow(LocationState.LocationResult.Loading), nwcFilterAssembler = nwcFilters, - otsResolverBuilder = otsResolver, + otsResolverBuilder = EmptyOtsResolverBuilder, cache = LocalCache, client = client, scope = scope, @@ -1694,8 +1697,6 @@ fun mockVitorAccountViewModel(): AccountViewModel { val scope = rememberCoroutineScope() - val otsResolver = DefaultOtsResolverBuilder() - val uiState = UiSettingsState( uiSettingsFlow = UiSettingsFlow(), @@ -1718,7 +1719,7 @@ fun mockVitorAccountViewModel(): AccountViewModel { signer = NostrSignerInternal(keyPair), geolocationFlow = MutableStateFlow(LocationState.LocationResult.Loading), nwcFilterAssembler = nwcFilters, - otsResolverBuilder = otsResolver, + otsResolverBuilder = EmptyOtsResolverBuilder, cache = LocalCache, client = EmptyNostrClient, scope = scope, @@ -1734,3 +1735,36 @@ fun mockVitorAccountViewModel(): AccountViewModel { vitorCache = it } } + +val EmptyOtsResolverBuilder = + object : OtsResolverBuilder { + override fun build(): OtsResolver = + OtsResolver( + explorer = + object : BitcoinExplorer { + override suspend fun block(hash: String): BlockHeader { + TODO("Not yet implemented") + } + + override suspend fun blockHash(height: Int): String { + TODO("Not yet implemented") + } + }, + calendar = + object : RemoteCalendar { + override suspend fun submit( + url: String, + digest: ByteArray, + ): Timestamp { + TODO("Not yet implemented") + } + + override suspend fun getTimestamp( + url: String, + commitment: ByteArray, + ): Timestamp { + TODO("Not yet implemented") + } + }, + ) + } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt index cd12ea1596..0bf7a6cb98 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn -import android.util.Log import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note @@ -37,6 +36,7 @@ import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent import com.vitorpamplona.quartz.nip57Zaps.PrivateZapCache import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException class EventProcessor( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoggedInPage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoggedInPage.kt index 17cf60ed1f..23a3da0e89 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoggedInPage.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/LoggedInPage.kt @@ -25,7 +25,6 @@ import android.app.Activity import android.content.ActivityNotFoundException import android.content.Intent import android.os.Build -import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.runtime.Composable @@ -53,6 +52,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.datasource.Discove import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.HomeFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.datasource.VideoFilterAssemblerSubscription import com.vitorpamplona.quartz.nip55AndroidSigner.client.IActivityLauncher +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.launch @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/DrawAuthorInfo.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/DrawAuthorInfo.kt index 64352fb5e9..5ec93bbe9a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/DrawAuthorInfo.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/DrawAuthorInfo.kt @@ -36,7 +36,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.layouts.UserDisplayNameLayout import com.vitorpamplona.amethyst.ui.theme.Size20dp import com.vitorpamplona.amethyst.ui.theme.Size5Modifier -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList @Composable fun DrawAuthorInfo( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChangeChannelMetadataNote.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChangeChannelMetadataNote.kt index 73753a70b3..84e9a7d290 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChangeChannelMetadataNote.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderChangeChannelMetadataNote.kt @@ -27,7 +27,7 @@ import androidx.compose.ui.graphics.Color import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelMetadataEvent @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderCreateChannelNote.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderCreateChannelNote.kt index 7c4c249165..ee8818c0fa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderCreateChannelNote.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderCreateChannelNote.kt @@ -66,12 +66,12 @@ import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonRow import com.vitorpamplona.amethyst.ui.theme.largeProfilePictureModifier +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent import com.vitorpamplona.quartz.nip28PublicChat.base.ChannelDataNorm diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderEncryptedFile.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderEncryptedFile.kt index 188edfcaef..f48d0b3afd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderEncryptedFile.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderEncryptedFile.kt @@ -40,10 +40,10 @@ import com.vitorpamplona.amethyst.ui.components.ZoomableContentView import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.stringRes -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList import com.vitorpamplona.quartz.nip17Dm.files.ChatMessageEncryptedFileHeaderEvent -import com.vitorpamplona.quartz.nip17Dm.files.encryption.AESGCM import com.vitorpamplona.quartz.nip31Alts.alt +import com.vitorpamplona.quartz.utils.ciphers.AESGCM import kotlinx.collections.immutable.persistentListOf @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderRegularTextNote.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderRegularTextNote.kt index 5bd75f486a..f704649b76 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderRegularTextNote.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderRegularTextNote.kt @@ -33,8 +33,8 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.note.LoadDecryptedContentOrNull import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.stringRes -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists @Composable fun RenderRegularTextNote( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/dal/ChatroomFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/dal/ChatroomFeedViewModel.kt index 5c277bf08d..f2b8973ac9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/dal/ChatroomFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/dal/ChatroomFeedViewModel.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.dal -import android.util.Log import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider @@ -32,6 +31,7 @@ import com.vitorpamplona.amethyst.ui.dal.ListChange import com.vitorpamplona.amethyst.ui.feeds.FeedContentState import com.vitorpamplona.amethyst.ui.feeds.InvalidatableContent import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt index f5dcda6239..40b51d993c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send import android.content.Context -import android.util.Log import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -89,6 +88,7 @@ import com.vitorpamplona.quartz.nip57Zaps.zapraiser.zapraiserAmount import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent import com.vitorpamplona.quartz.nip92IMeta.imetas import com.vitorpamplona.quartz.utils.Hex +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileSender.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileSender.kt index 5fdd6d6478..0033956c97 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileSender.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileSender.kt @@ -27,9 +27,9 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.IMetaA import com.vitorpamplona.quartz.nip04Dm.messages.PrivateDmEvent import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKey import com.vitorpamplona.quartz.nip17Dm.files.ChatMessageEncryptedFileHeaderEvent -import com.vitorpamplona.quartz.nip17Dm.files.encryption.AESGCM import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarning +import com.vitorpamplona.quartz.utils.ciphers.AESGCM class ChatFileSender( val chatroom: ChatroomKey, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileUploader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileUploader.kt index db5c43d959..8f79d77754 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileUploader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/ChatFileUploader.kt @@ -27,7 +27,7 @@ import com.vitorpamplona.amethyst.service.uploads.MediaCompressor import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.utils.ChatFileUploadState import com.vitorpamplona.amethyst.ui.stringRes -import com.vitorpamplona.quartz.nip17Dm.files.encryption.AESGCM +import com.vitorpamplona.quartz.utils.ciphers.AESGCM class ChatFileUploader( val account: Account, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/SuccessfulUploads.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/SuccessfulUploads.kt index 50fb293243..5613289903 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/SuccessfulUploads.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/upload/SuccessfulUploads.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.privateDM.send.upload import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator -import com.vitorpamplona.quartz.nip17Dm.files.encryption.AESGCM +import com.vitorpamplona.quartz.utils.ciphers.AESGCM class SuccessfulUploads( val result: UploadOrchestrator.OrchestratorResult.ServerResult, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/ChannelView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/ChannelView.kt index e147ad2c1e..5c14da3232 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/ChannelView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/ChannelView.kt @@ -41,7 +41,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.dataso import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.send.ChannelNewMessageViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.send.EditFieldRow import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.core.Address @Composable fun LiveActivityChannelView( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/LiveActivityChannelScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/LiveActivityChannelScreen.kt index cef2058a19..67ce16968e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/LiveActivityChannelScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/LiveActivityChannelScreen.kt @@ -32,7 +32,7 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.note.LoadLiveActivityChannel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.nip53LiveActivities.header.LiveActivityTopBar -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.core.Address @Composable fun LiveActivityChannelScreen( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LongLiveActivityChannelHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LongLiveActivityChannelHeader.kt index b6f1a24de5..97fa81a62c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LongLiveActivityChannelHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip53LiveActivities/header/LongLiveActivityChannelHeader.kt @@ -60,8 +60,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutabl import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.Size25dp +import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags -import com.vitorpamplona.quartz.nip02FollowList.toImmutableListOfLists import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.ParticipantTag import kotlinx.collections.immutable.ImmutableList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt index 41a6955cf7..92526bc53e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.send import android.content.Context -import android.util.Log import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -71,6 +70,7 @@ import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.geohash.geohash import com.vitorpamplona.quartz.nip01Core.tags.geohash.getGeoHash import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags +import com.vitorpamplona.quartz.nip01Core.tags.people.toPTag import com.vitorpamplona.quartz.nip01Core.tags.references.references import com.vitorpamplona.quartz.nip10Notes.content.findHashtags import com.vitorpamplona.quartz.nip10Notes.content.findNostrUris @@ -89,6 +89,7 @@ import com.vitorpamplona.quartz.nip57Zaps.splits.ZapSplitSetup import com.vitorpamplona.quartz.nip57Zaps.splits.zapSplitSetup import com.vitorpamplona.quartz.nip57Zaps.zapraiser.zapraiserAmount import com.vitorpamplona.quartz.nip92IMeta.imetas +import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.StateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/CommunityScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/CommunityScreen.kt index 535cec38c5..e1d8cc2fed 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/CommunityScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/communities/CommunityScreen.kt @@ -65,7 +65,7 @@ import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size35dp import com.vitorpamplona.amethyst.ui.theme.TabRowHeight import com.vitorpamplona.amethyst.ui.theme.isLight -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.core.Address import kotlinx.coroutines.launch @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/LiveActivityCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/LiveActivityCard.kt index 26d23d3967..58ec5f2a15 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/LiveActivityCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/LiveActivityCard.kt @@ -68,7 +68,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.CheckIfVideoIsOnline import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.QuoteBorder -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.ParticipantTag import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.StatusTag diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/DiscoverCommunityFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/DiscoverCommunityFeedFilter.kt index 1e92992717..eb649fe223 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/DiscoverCommunityFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/DiscoverCommunityFeedFilter.kt @@ -25,8 +25,8 @@ import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.dal.AdditiveFeedFilter import com.vitorpamplona.amethyst.ui.dal.FilterByListParams +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip51Lists.muteList.MuteListEvent import com.vitorpamplona.quartz.nip51Lists.peopleList.PeopleListEvent import com.vitorpamplona.quartz.nip72ModCommunities.approval.CommunityPostApprovalEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/subassemblies/FilterCommunitiesByCommunity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/subassemblies/FilterCommunitiesByCommunity.kt index 40d6bf4575..5a1f16ded4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/subassemblies/FilterCommunitiesByCommunity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/subassemblies/FilterCommunitiesByCommunity.kt @@ -22,10 +22,10 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip72Communities. import com.vitorpamplona.amethyst.model.topNavFeeds.noteBased.community.SingleCommunityTopNavPerRelayFilterSet import com.vitorpamplona.amethyst.service.relays.SincePerRelayMap +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent fun filterClassifiedsByCommunity( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt index 4833ab0d08..1c8dd17b6b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip99Classifieds import android.content.Context -import android.util.Log import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -88,6 +87,7 @@ import com.vitorpamplona.quartz.nip99Classifieds.ProductImageMeta import com.vitorpamplona.quartz.nip99Classifieds.image import com.vitorpamplona.quartz.nip99Classifieds.tags.ConditionTag import com.vitorpamplona.quartz.nip99Classifieds.tags.PriceTag +import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt index 5976ed234e..d9d05bb3ab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.home import android.content.Context -import android.util.Log import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateListOf @@ -117,6 +116,7 @@ import com.vitorpamplona.quartz.nip94FileMetadata.mimeType import com.vitorpamplona.quartz.nip94FileMetadata.originalHash import com.vitorpamplona.quartz.nip94FileMetadata.sensitiveContent import com.vitorpamplona.quartz.nip94FileMetadata.size +import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.StateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt index 4ee5b7973b..3d6ef0545f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications -import android.util.Log import androidx.compose.runtime.Immutable import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable @@ -48,6 +47,7 @@ import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelMetadataEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent import com.vitorpamplona.quartz.nip58Badges.BadgeAwardEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedState.kt index 7baa1fee90..8eccf0ada4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedState.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.firstFullCharOrEmoji import com.vitorpamplona.amethyst.ui.feeds.LoadedFeedState -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableMap diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryState.kt index 1e17c4c48e..16447e5f36 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryState.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications -import android.util.Log import androidx.compose.runtime.Stable import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModel import com.patrykandpatrick.vico.core.cartesian.data.LineCartesianLayerModel @@ -41,6 +40,7 @@ import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent import com.vitorpamplona.quartz.nip18Reposts.RepostEvent import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt index 5925e9f501..3231287d24 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.publicMessages import android.content.Context -import android.util.Log import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -103,6 +102,7 @@ import com.vitorpamplona.quartz.nip94FileMetadata.originalHash import com.vitorpamplona.quartz.nip94FileMetadata.sensitiveContent import com.vitorpamplona.quartz.nip94FileMetadata.size import com.vitorpamplona.quartz.utils.Hex +import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.StateFlow diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DrawAdditionalInfo.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DrawAdditionalInfo.kt index 59fb554333..c38c547286 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DrawAdditionalInfo.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/header/DrawAdditionalInfo.kt @@ -65,7 +65,7 @@ import com.vitorpamplona.amethyst.ui.theme.Size15Modifier import com.vitorpamplona.amethyst.ui.theme.Size25Modifier import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.placeholderText -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList import com.vitorpamplona.quartz.nip39ExtIdentities.GitHubIdentity import com.vitorpamplona.quartz.nip39ExtIdentities.IdentityClaimTag import com.vitorpamplona.quartz.nip39ExtIdentities.MastodonIdentity diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/RelayFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/RelayFeedViewModel.kt index 2ebbcd3fef..81123359e0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/RelayFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/relays/RelayFeedViewModel.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.relays -import android.util.Log import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.mutableStateOf @@ -32,6 +31,7 @@ import com.vitorpamplona.amethyst.ui.feeds.InvalidatableContent import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip17Dm.settings.ChatMessageRelayListEvent import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview @@ -41,7 +41,6 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.transformLatest diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/LnZapFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/LnZapFeedViewModel.kt index b7769fb46a..3e910af2c7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/LnZapFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/LnZapFeedViewModel.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.zaps -import android.util.Log import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -29,6 +28,7 @@ import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.ui.dal.FeedFilter import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists import com.vitorpamplona.ammolite.relays.BundledUpdate +import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/QrCodeScanner.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/QrCodeScanner.kt index 3505d8b848..a1324e3582 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/QrCodeScanner.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/qrcode/QrCodeScanner.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode -import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect @@ -32,6 +31,7 @@ import com.vitorpamplona.amethyst.ui.navigation.routes.Route import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.uriToRoute +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt index e39803d0b9..623fd1caf5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt @@ -72,12 +72,12 @@ import com.vitorpamplona.amethyst.ui.theme.Size10dp import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.StdPadding import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayDebugMessage import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStats import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList import kotlinx.collections.immutable.toImmutableList @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/StringFeedViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/StringFeedViewModel.kt index 8c9d935455..cc999d7977 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/StringFeedViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/StringFeedViewModel.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings -import android.util.Log import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.mutableStateOf @@ -32,6 +31,7 @@ import com.vitorpamplona.amethyst.ui.dal.FeedFilter import com.vitorpamplona.amethyst.ui.feeds.InvalidatableContent import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists import com.vitorpamplona.ammolite.relays.BundledUpdate +import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenAccountsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenAccountsFeedFilter.kt index b1c001bb8b..38d5541aef 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenAccountsFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/dal/HiddenAccountsFeedFilter.kt @@ -20,11 +20,11 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.dal -import android.util.Log import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.dal.FeedFilter +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException class HiddenAccountsFeedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/ExternalSignerButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/ExternalSignerButton.kt index d3b2d274a2..4285dd0872 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/ExternalSignerButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/login/ExternalSignerButton.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedOff.login import android.app.Activity -import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Box @@ -38,6 +37,7 @@ import com.vitorpamplona.amethyst.ui.theme.Size40dp import com.vitorpamplona.quartz.nip55AndroidSigner.api.PubKeyResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.client.ExternalSignerLogin +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException import kotlinx.coroutines.launch diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/tor/TorService.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/tor/TorService.kt index f285716827..ad40bbbb77 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/tor/TorService.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/tor/TorService.kt @@ -26,7 +26,7 @@ import android.content.Context.BIND_AUTO_CREATE import android.content.Intent import android.content.ServiceConnection import android.os.IBinder -import android.util.Log +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.delay diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/tor/TorSettingsFlow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/tor/TorSettingsFlow.kt index d4d765d26c..5c7c0a361a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/tor/TorSettingsFlow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/tor/TorSettingsFlow.kt @@ -38,7 +38,7 @@ class TorSettingsFlow( val nip05VerificationsViaTor: MutableStateFlow = MutableStateFlow(false), val nip96UploadsViaTor: MutableStateFlow = MutableStateFlow(false), ) { - // emits at every change in any of the propertyes. + // emits at every change in any of the properties. val propertyWatchFlow = combine( listOf( diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 97fac20ca0..3d47e438d5 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -1229,6 +1229,7 @@ Download Failed to open file No torrent apps installed to open and download the file. + Event doesn\'t have enough information to build a magnet link Select a list to filter the feed diff --git a/amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationReceiverService.kt b/amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationReceiverService.kt index 58c1a38449..119f0d23ab 100644 --- a/amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationReceiverService.kt +++ b/amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationReceiverService.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.amethyst.service.notifications import android.app.NotificationManager -import android.util.Log import android.util.LruCache import androidx.core.content.ContextCompat import com.google.firebase.messaging.FirebaseMessagingService @@ -30,6 +29,7 @@ import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt b/amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt index 3973f07587..478da0243b 100644 --- a/amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt +++ b/amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationUtils.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.amethyst.service.notifications -import android.util.Log import com.google.firebase.messaging.FirebaseMessaging import com.vitorpamplona.amethyst.AccountInfo import com.vitorpamplona.amethyst.service.retryIfException +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.tasks.await import okhttp3.OkHttpClient diff --git a/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt index 20c9b19cdb..31f5553f86 100644 --- a/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt +++ b/amethyst/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt @@ -62,7 +62,7 @@ import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.Font14SP import com.vitorpamplona.amethyst.ui.theme.lessImportantLink -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/NewMessageTaggerKeyParseTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/NewMessageTaggerKeyParseTest.kt index 3ab1f02496..216691ae09 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/NewMessageTaggerKeyParseTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/NewMessageTaggerKeyParseTest.kt @@ -24,7 +24,7 @@ import com.vitorpamplona.amethyst.model.LocalCache.getOrCreateAddressableNoteInt import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.actions.Dao import com.vitorpamplona.amethyst.ui.actions.NewMessageTagger -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip17Dm.settings.ChatMessageRelayListEvent import com.vitorpamplona.quartz.nip19Bech32.entities.NNote import com.vitorpamplona.quartz.nip19Bech32.entities.NPub diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/UrlDecoderTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/UrlDecoderTest.kt index f1dddd8f1e..a1b3a9c98f 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/UrlDecoderTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/UrlDecoderTest.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.amethyst -import junit.framework.TestCase.assertEquals +import org.junit.Assert.assertEquals import org.junit.Test import java.net.URLDecoder import java.net.URLEncoder diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/components/MediaCompressorTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/components/MediaCompressorTest.kt index 5b07e82f2a..28d06e8267 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/components/MediaCompressorTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/components/MediaCompressorTest.kt @@ -37,9 +37,9 @@ import io.mockk.mockkObject import io.mockk.mockkStatic import io.mockk.unmockkAll import io.mockk.verify -import junit.framework.TestCase.assertEquals import kotlinx.coroutines.test.runTest import org.junit.After +import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Ignore import org.junit.Test diff --git a/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/BundledUpdate.kt b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/BundledUpdate.kt index 9c0076bd7c..66dc0d04e1 100644 --- a/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/BundledUpdate.kt +++ b/ammolite/src/main/java/com/vitorpamplona/ammolite/relays/BundledUpdate.kt @@ -20,9 +20,9 @@ */ package com.vitorpamplona.ammolite.relays -import android.util.Log import androidx.compose.runtime.Stable import com.vitorpamplona.ammolite.service.checkNotInMainThread +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope diff --git a/benchmark/build.gradle b/benchmark/build.gradle index d008883b7c..cd0571b30d 100644 --- a/benchmark/build.gradle +++ b/benchmark/build.gradle @@ -24,7 +24,7 @@ android { targetCompatibility JavaVersion.VERSION_21 } - sourceSets.androidTest.resources.srcDirs += ["../quartz/src/androidDeviceTest/resources"] + sourceSets.androidTest.resources.srcDirs += ["../quartz/src/androidInstrumentedTest/resources"] testBuildType = "benchmark" buildTypes { diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/amethyst/benchmark/RichTextParserBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/amethyst/benchmark/RichTextParserBenchmark.kt index b7898ee416..87e971712c 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/amethyst/benchmark/RichTextParserBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/amethyst/benchmark/RichTextParserBenchmark.kt @@ -29,10 +29,10 @@ import com.vitorpamplona.amethyst.commons.richtext.HashTagSegment import com.vitorpamplona.amethyst.commons.richtext.ImageSegment import com.vitorpamplona.amethyst.commons.richtext.LinkSegment import com.vitorpamplona.amethyst.commons.richtext.RichTextParser -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists import junit.framework.TestCase.assertNull -import junit.framework.TestCase.assertTrue +import org.junit.Assert.assertTrue import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/BaseLargeCacheBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/BaseLargeCacheBenchmark.kt index b64308936f..95a40ff46d 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/BaseLargeCacheBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/BaseLargeCacheBenchmark.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.quartz.benchmark import com.fasterxml.jackson.module.kotlin.readValue import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper +import com.vitorpamplona.quartz.utils.cache.LargeCache import org.junit.Assert.assertTrue import java.util.function.Consumer import java.util.zip.GZIPInputStream @@ -33,9 +33,9 @@ open class BaseLargeCacheBenchmark { companion object { fun getEventDB(): List { // This file includes duplicates - val fullDBInputStream = javaClass.classLoader?.getResourceAsStream("nostr_vitor_startup_data.json") + val fullDBInputStream = javaClass.classLoader!!.getResourceAsStream("nostr_vitor_startup_data.json") - return JsonMapper.mapper.readValue>( + return JacksonMapper.mapper.readValue>( GZIPInputStream(fullDBInputStream), ) } diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/BechBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/BechBenchmark.kt index 14e8ca7c59..d83e37380e 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/BechBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/BechBenchmark.kt @@ -26,7 +26,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.nip19Bech32.bech32.bechToBytes import com.vitorpamplona.quartz.nip19Bech32.toNpub import com.vitorpamplona.quartz.utils.Hex -import junit.framework.TestCase.assertEquals +import org.junit.Assert.assertEquals import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/CacheBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/CacheBenchmark.kt index 2fbe69d92d..060519ab5b 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/CacheBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/CacheBenchmark.kt @@ -26,8 +26,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.fasterxml.jackson.module.kotlin.readValue import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper +import com.vitorpamplona.quartz.utils.cache.LargeCache import org.junit.Assert.assertTrue import org.junit.Rule import org.junit.Test @@ -43,7 +43,7 @@ open class BaseCacheBenchmark { // This file includes duplicates val fullDBInputStream = javaClass.classLoader?.getResourceAsStream("nostr_vitor_startup_data.json") - return JsonMapper.mapper.readValue>( + return JacksonMapper.mapper.readValue>( GZIPInputStream(fullDBInputStream), ) } diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/ChaCha20Benchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/ChaCha20Benchmark.kt index 7b572b34e3..9fec039656 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/ChaCha20Benchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/ChaCha20Benchmark.kt @@ -58,12 +58,15 @@ class ChaCha20Benchmark { } } + /* + Removed in the conversion to KMP @Test fun encryptNative() { benchmarkRule.measureRepeated { chaCha.encryptNative(padded, messageKeys.chachaNonce, messageKeys.chachaKey) } } + */ @Test fun decryptLibSodium() { @@ -72,10 +75,13 @@ class ChaCha20Benchmark { } } + /* + Removed in the conversion to KMP @Test fun decryptNative() { benchmarkRule.measureRepeated { chaCha.decryptNative(padded, messageKeys.chachaNonce, messageKeys.chachaKey) } } + */ } diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/ContainsBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/ContainsBenchmark.kt index 3bc743eae3..2ca0f06bc4 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/ContainsBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/ContainsBenchmark.kt @@ -25,7 +25,7 @@ import androidx.benchmark.junit4.measureRepeated import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.utils.DualCase import com.vitorpamplona.quartz.utils.containsAny -import junit.framework.TestCase.assertTrue +import org.junit.Assert.assertTrue import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EnsureTest.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EnsureTest.kt index 9112475910..2b4d22b3d2 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EnsureTest.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EnsureTest.kt @@ -24,7 +24,7 @@ import androidx.benchmark.junit4.BenchmarkRule import androidx.benchmark.junit4.measureRepeated import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.utils.ensure -import junit.framework.TestCase.assertTrue +import org.junit.Assert.assertTrue import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -45,7 +45,6 @@ class EnsureTest { "0123456789abcdefABCDEF".forEach { this[it.code] = true } } - @JvmStatic fun String.isHex() = all { isHexChar[it.code] } } diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventBenchmark.kt index d7489336bc..0e61281d63 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventBenchmark.kt @@ -23,14 +23,17 @@ package com.vitorpamplona.quartz.benchmark import androidx.benchmark.junit4.BenchmarkRule import androidx.benchmark.junit4.measureRepeated import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.vitorpamplona.quartz.EventFactory -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper -import com.vitorpamplona.quartz.nip01Core.verify -import com.vitorpamplona.quartz.nip01Core.verifyId -import com.vitorpamplona.quartz.nip01Core.verifySignature +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper +import com.vitorpamplona.quartz.nip01Core.crypto.verify +import com.vitorpamplona.quartz.nip01Core.crypto.verifyId +import com.vitorpamplona.quartz.nip01Core.crypto.verifySignature +import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper +import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.EventMessage +import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.Message import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent +import com.vitorpamplona.quartz.utils.EventFactory import com.vitorpamplona.quartz.utils.TimeUtils -import junit.framework.TestCase.assertTrue +import org.junit.Assert.assertTrue import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -48,28 +51,26 @@ class EventBenchmark { @Test fun parseComplete() { benchmarkRule.measureRepeated { - val tree = JsonMapper.mapper.readTree(reqResponseEvent) - val event = JsonMapper.fromJson(tree[2]) + val event = (OptimizedJsonMapper.fromJsonTo(reqResponseEvent) as EventMessage).event assertTrue(event.verify()) } } @Test fun parseREQString() { - benchmarkRule.measureRepeated { JsonMapper.mapper.readTree(reqResponseEvent) } + benchmarkRule.measureRepeated { JacksonMapper.mapper.readTree(reqResponseEvent) } } @Test fun parseEvent() { - val msg = JsonMapper.mapper.readTree(reqResponseEvent) + val msg = JacksonMapper.mapper.readTree(reqResponseEvent) - benchmarkRule.measureRepeated { JsonMapper.fromJson(msg[2]) } + benchmarkRule.measureRepeated { JacksonMapper.fromJson(msg[2]) } } @Test fun checkId() { - val msg = JsonMapper.mapper.readTree(reqResponseEvent) - val event = JsonMapper.fromJson(msg[2]) + val event = (OptimizedJsonMapper.fromJsonTo(reqResponseEvent) as EventMessage).event benchmarkRule.measureRepeated { // Should pass assertTrue(event.verifyId()) @@ -78,8 +79,7 @@ class EventBenchmark { @Test fun checkSignature() { - val msg = JsonMapper.mapper.readTree(reqResponseEvent) - val event = JsonMapper.fromJson(msg[2]) + val event = (OptimizedJsonMapper.fromJsonTo(reqResponseEvent) as EventMessage).event benchmarkRule.measureRepeated { // Should pass assertTrue(event.verifySignature()) diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventCmdHasherBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventCmdHasherBenchmark.kt index 5b07307dd8..b4ff086124 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventCmdHasherBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventCmdHasherBenchmark.kt @@ -24,12 +24,13 @@ import androidx.benchmark.junit4.BenchmarkRule import androidx.benchmark.junit4.measureRepeated import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.generateId -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper +import com.vitorpamplona.quartz.nip01Core.crypto.generateId +import com.vitorpamplona.quartz.nip01Core.crypto.verifyId import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.EventMessage -import com.vitorpamplona.quartz.nip01Core.verifyId +import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.Message import junit.framework.TestCase.assertNotNull -import junit.framework.TestCase.assertTrue +import org.junit.Assert.assertTrue import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -46,7 +47,7 @@ class EventCmdHasherBenchmark { @Test fun checkIDHashKind1WithoutTags() { - val event = EventMessage.parse(JsonMapper.mapper.readTree(reqResponseEvent)).event + val event = (OptimizedJsonMapper.fromJsonTo(reqResponseEvent) as EventMessage).event benchmarkRule.measureRepeated { // Should pass diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventVerifySerializer.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventVerifySerializer.kt index 6fa96f183e..b366d40daa 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventVerifySerializer.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventVerifySerializer.kt @@ -24,7 +24,7 @@ import androidx.benchmark.junit4.BenchmarkRule import androidx.benchmark.junit4.measureRepeated import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.crypto.EventHasher +import com.vitorpamplona.quartz.nip01Core.crypto.EventHasherSerializer import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -44,7 +44,7 @@ class EventVerifySerializer { fun serializeToCheckId() { val event = Event.fromJson(largeKind1Event) benchmarkRule.measureRepeated { - EventHasher.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) + EventHasherSerializer.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) } } @@ -52,7 +52,7 @@ class EventVerifySerializer { fun fastSerializeToCheckId() { val event = Event.fromJson(largeKind1Event) benchmarkRule.measureRepeated { - EventHasher.fastMakeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) + EventHasherSerializer.fastMakeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) } } } diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapBenchmark.kt index cad8498c35..2fbc91c9a2 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapBenchmark.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.quartz.benchmark import androidx.benchmark.junit4.BenchmarkRule import androidx.benchmark.junit4.measureRepeated import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.vitorpamplona.quartz.nip01Core.checkSignature import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair +import com.vitorpamplona.quartz.nip01Core.crypto.checkSignature import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip17Dm.NIP17Factory diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapReceivingBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapReceivingBenchmark.kt index 3472b7794e..9b945d54c5 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapReceivingBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapReceivingBenchmark.kt @@ -26,11 +26,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair +import com.vitorpamplona.quartz.nip01Core.crypto.verifyId +import com.vitorpamplona.quartz.nip01Core.crypto.verifySignature import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip01Core.tags.people.PTag -import com.vitorpamplona.quartz.nip01Core.verifyId -import com.vitorpamplona.quartz.nip01Core.verifySignature import com.vitorpamplona.quartz.nip17Dm.messages.ChatMessageEvent import com.vitorpamplona.quartz.nip17Dm.messages.changeSubject import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarning diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HintIndexerBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HintIndexerBenchmark.kt index 28ea473b66..3eeaef66b3 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HintIndexerBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HintIndexerBenchmark.kt @@ -31,7 +31,6 @@ import com.vitorpamplona.quartz.utils.RandomInstance import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import java.nio.charset.Charset @RunWith(AndroidJUnit4::class) class HintIndexerBenchmark { @@ -46,10 +45,10 @@ class HintIndexerBenchmark { } val relays = - javaClass.classLoader - ?.getResourceAsStream("relayDB.txt")!! - .readBytes() - .toString(Charset.forName("utf-8")) + javaClass.classLoader!! + .getResourceAsStream("relayDB.txt") + .bufferedReader() + .use { it.readText() } .split("\n") .mapNotNull(RelayUrlNormalizer::normalizeOrNull) } diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HkdfBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HkdfBenchmark.kt index 207b9e8bf3..38e5807483 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HkdfBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HkdfBenchmark.kt @@ -61,6 +61,7 @@ class HkdfBenchmark { } } + /* @Test fun hkdfExpandOld() { val hkdf = Hkdf() @@ -68,6 +69,7 @@ class HkdfBenchmark { hkdf.expand(sharedKey, encrypted.nonce, 76) } } + */ @Test fun hkdfExtract() { diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/LargeDBInsertBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/LargeDBInsertBenchmark.kt index 8b5c4cb50b..36f2dee27e 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/LargeDBInsertBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/LargeDBInsertBenchmark.kt @@ -22,7 +22,6 @@ package com.vitorpamplona.quartz.benchmark import android.content.Context import android.database.sqlite.SQLiteException -import android.util.Log import androidx.benchmark.junit4.BenchmarkRule import androidx.benchmark.junit4.measureRepeated import androidx.test.core.app.ApplicationProvider @@ -31,6 +30,7 @@ import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.store.sqlite.EventStore import com.vitorpamplona.quartz.nip09Deletions.DeletionEvent import com.vitorpamplona.quartz.nip40Expiration.isExpired +import com.vitorpamplona.quartz.utils.Log import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -49,7 +49,7 @@ class LargeDBInsertBenchmark : BaseLargeCacheBenchmark() { val context = ApplicationProvider.getApplicationContext() benchmarkRule.measureRepeated { val db = - this.runWithTimingDisabled { + this.runWithMeasurementDisabled { val db = EventStore(context, "test1.db") db.store.clearDB() db @@ -61,7 +61,7 @@ class LargeDBInsertBenchmark : BaseLargeCacheBenchmark() { Log.w("LargeDBInsertBenchmark", "Error inserting event: ${e.message} for event: $event") } } - this.runWithTimingDisabled { + this.runWithMeasurementDisabled { db.store.clearDB() db.close() } @@ -82,7 +82,7 @@ class LargeDBInsertBenchmark : BaseLargeCacheBenchmark() { benchmarkRule.measureRepeated { val db = - this.runWithTimingDisabled { + this.runWithMeasurementDisabled { val db = EventStore(context, "test1.db") db.store.clearDB() toBeDeletedEvents.forEach { event -> @@ -104,7 +104,7 @@ class LargeDBInsertBenchmark : BaseLargeCacheBenchmark() { } } - runWithTimingDisabled { + runWithMeasurementDisabled { db.store.clearDB() db.close() } diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/LargeDBQueryingBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/LargeDBQueryingBenchmark.kt index 805cb08b5d..8d31505130 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/LargeDBQueryingBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/LargeDBQueryingBenchmark.kt @@ -22,7 +22,6 @@ package com.vitorpamplona.quartz.benchmark import android.content.Context import android.database.sqlite.SQLiteException -import android.util.Log import androidx.benchmark.junit4.BenchmarkRule import androidx.benchmark.junit4.measureRepeated import androidx.test.core.app.ApplicationProvider @@ -32,6 +31,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.store.sqlite.EventStore import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent +import com.vitorpamplona.quartz.utils.Log import org.junit.After import org.junit.Before import org.junit.Rule diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/Sha256Benchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/Sha256Benchmark.kt index d49a74efd0..49302e5edc 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/Sha256Benchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/Sha256Benchmark.kt @@ -24,7 +24,7 @@ import androidx.benchmark.junit4.BenchmarkRule import androidx.benchmark.junit4.measureRepeated import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.crypto.EventHasher +import com.vitorpamplona.quartz.nip01Core.crypto.EventHasherSerializer import com.vitorpamplona.quartz.utils.sha256.sha256 import junit.framework.TestCase.assertNotNull import org.junit.Rule @@ -46,7 +46,7 @@ class Sha256Benchmark { @Test fun sha256Pool() { val event = Event.fromJson(largeKind1Event) - val byteArray = EventHasher.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content).toByteArray() + val byteArray = EventHasherSerializer.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content).toByteArray() benchmarkRule.measureRepeated { // Should pass @@ -57,7 +57,7 @@ class Sha256Benchmark { @Test fun sha256NewEachTime() { val event = Event.fromJson(largeKind1Event) - val byteArray = EventHasher.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content).toByteArray() + val byteArray = EventHasherSerializer.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content).toByteArray() benchmarkRule.measureRepeated { val digest = MessageDigest.getInstance("SHA-256") @@ -68,7 +68,7 @@ class Sha256Benchmark { @Test fun sha256Reuse() { val event = Event.fromJson(largeKind1Event) - val byteArray = EventHasher.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content).toByteArray() + val byteArray = EventHasherSerializer.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content).toByteArray() val digest = MessageDigest.getInstance("SHA-256") diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/SignVerifyBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/SignVerifyBenchmark.kt index 5981d98ff0..3f414b7ef6 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/SignVerifyBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/SignVerifyBenchmark.kt @@ -28,7 +28,7 @@ import com.vitorpamplona.quartz.nip01Core.crypto.Nip01 import com.vitorpamplona.quartz.utils.RandomInstance import com.vitorpamplona.quartz.utils.sha256.sha256 import junit.framework.TestCase.assertNotNull -import junit.framework.TestCase.assertTrue +import org.junit.Assert.assertTrue import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith diff --git a/build.gradle b/build.gradle index 4acc357f81..2b3bb74b3c 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ plugins { alias(libs.plugins.jetbrainsComposeCompiler) apply false alias(libs.plugins.kotlinMultiplatform) apply false alias(libs.plugins.androidKotlinMultiplatformLibrary) apply false + alias(libs.plugins.serialization) } allprojects { diff --git a/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/compose/TextFieldValueExtensionTest.kt b/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/compose/TextFieldValueExtensionTest.kt index 57b5218c8a..61e4fb2d99 100644 --- a/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/compose/TextFieldValueExtensionTest.kt +++ b/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/compose/TextFieldValueExtensionTest.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.amethyst.commons.compose import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.input.TextFieldValue import androidx.test.ext.junit.runners.AndroidJUnit4 -import junit.framework.TestCase.assertEquals +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith diff --git a/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/preview/BlurhashTest.kt b/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/preview/BlurhashTest.kt index 678a654fbc..d0f9614e7f 100644 --- a/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/preview/BlurhashTest.kt +++ b/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/preview/BlurhashTest.kt @@ -26,9 +26,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.amethyst.commons.blurhash.BlurHashDecoder import com.vitorpamplona.amethyst.commons.blurhash.BlurHashDecoderOld import com.vitorpamplona.amethyst.commons.blurhash.toBlurhash -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertTrue import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import kotlin.math.roundToInt diff --git a/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/richtext/ExpandableTextCutOffCalculatorTest.kt b/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/richtext/ExpandableTextCutOffCalculatorTest.kt index e8af359ba0..61febbf992 100644 --- a/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/richtext/ExpandableTextCutOffCalculatorTest.kt +++ b/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/richtext/ExpandableTextCutOffCalculatorTest.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.commons.richtext import androidx.test.ext.junit.runners.AndroidJUnit4 -import junit.framework.TestCase.assertEquals +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith diff --git a/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParserTest.kt b/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParserTest.kt index e756503f42..dc90095fbb 100644 --- a/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParserTest.kt +++ b/commons/src/androidTest/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParserTest.kt @@ -21,8 +21,8 @@ package com.vitorpamplona.amethyst.commons.richtext import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.vitorpamplona.quartz.nip02FollowList.EmptyTagList -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.EmptyTagList +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists import org.junit.Test import org.junit.runner.RunWith diff --git a/commons/src/main/java/com/vitorpamplona/amethyst/commons/emojicoder/EmojiCoder.kt b/commons/src/main/java/com/vitorpamplona/amethyst/commons/emojicoder/EmojiCoder.kt index 89da1ce7c8..7ab4a118d0 100644 --- a/commons/src/main/java/com/vitorpamplona/amethyst/commons/emojicoder/EmojiCoder.kt +++ b/commons/src/main/java/com/vitorpamplona/amethyst/commons/emojicoder/EmojiCoder.kt @@ -52,7 +52,6 @@ object EmojiCoder { charCode in VARIATION_SELECTOR_START..VARIATION_SELECTOR_END || charCode in VARIATION_SELECTOR_SUPPLEMENT_START..VARIATION_SELECTOR_SUPPLEMENT_END - @JvmStatic fun isCoded(text: String): Boolean { if (text.length <= 3) return false @@ -67,7 +66,6 @@ object EmojiCoder { return true } - @JvmStatic fun encode( emoji: String, text: String, @@ -83,7 +81,6 @@ object EmojiCoder { return emoji + String(out) } - @JvmStatic fun decode(text: String): String { val decoded = mutableListOf() @@ -107,7 +104,6 @@ object EmojiCoder { return String(decodedArray, Charsets.UTF_8) } - @JvmStatic fun cropToFirstMessage(text: String): String { val decoded = mutableListOf() diff --git a/commons/src/main/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParser.kt b/commons/src/main/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParser.kt index 6d17f3189e..fbc87e92c8 100644 --- a/commons/src/main/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParser.kt +++ b/commons/src/main/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParser.kt @@ -20,14 +20,13 @@ */ package com.vitorpamplona.amethyst.commons.richtext -import android.util.Log import android.util.Patterns import com.linkedin.urls.detection.UrlDetector import com.linkedin.urls.detection.UrlDetectorOptions import com.vitorpamplona.amethyst.commons.base64Image.Base64Image import com.vitorpamplona.amethyst.commons.emojicoder.EmojiCoder import com.vitorpamplona.quartz.experimental.inlineMetadata.Nip54InlineMetadata -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists import com.vitorpamplona.quartz.nip30CustomEmoji.CustomEmoji import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip36SensitiveContent.ContentWarningTag @@ -37,6 +36,7 @@ import com.vitorpamplona.quartz.nip94FileMetadata.tags.BlurhashTag import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag import com.vitorpamplona.quartz.nip94FileMetadata.tags.HashSha256Tag import com.vitorpamplona.quartz.nip94FileMetadata.tags.MimeTypeTag +import com.vitorpamplona.quartz.utils.Log import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList diff --git a/commons/src/main/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParserSegments.kt b/commons/src/main/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParserSegments.kt index 4bdc43ad7f..35c19442c3 100644 --- a/commons/src/main/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParserSegments.kt +++ b/commons/src/main/java/com/vitorpamplona/amethyst/commons/richtext/RichTextParserSegments.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.commons.richtext import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableMap import kotlinx.collections.immutable.ImmutableSet diff --git a/commons/src/main/java/com/vitorpamplona/amethyst/commons/robohash/RobohashAssembler.kt b/commons/src/main/java/com/vitorpamplona/amethyst/commons/robohash/RobohashAssembler.kt index 3f414bfd18..99e81fb854 100644 --- a/commons/src/main/java/com/vitorpamplona/amethyst/commons/robohash/RobohashAssembler.kt +++ b/commons/src/main/java/com/vitorpamplona/amethyst/commons/robohash/RobohashAssembler.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.commons.robohash -import android.util.Log import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding @@ -86,6 +85,7 @@ import com.vitorpamplona.amethyst.commons.robohash.parts.mouth7Happy import com.vitorpamplona.amethyst.commons.robohash.parts.mouth8Buttons import com.vitorpamplona.amethyst.commons.robohash.parts.mouth9Closed import com.vitorpamplona.quartz.utils.Hex +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.sha256.sha256 val Black = SolidColor(Color.Black) diff --git a/commons/src/test/java/com/vitorpamplona/amethyst/commons/Base83Test.kt b/commons/src/test/java/com/vitorpamplona/amethyst/commons/Base83Test.kt index a43b20b023..faaa1bf8a4 100644 --- a/commons/src/test/java/com/vitorpamplona/amethyst/commons/Base83Test.kt +++ b/commons/src/test/java/com/vitorpamplona/amethyst/commons/Base83Test.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.commons import com.vitorpamplona.amethyst.commons.blurhash.Base83 -import junit.framework.TestCase.assertEquals +import org.junit.Assert.assertEquals import org.junit.Test class Base83Test { diff --git a/commons/src/test/java/com/vitorpamplona/amethyst/commons/SRGBTest.kt b/commons/src/test/java/com/vitorpamplona/amethyst/commons/SRGBTest.kt index 1ba00329e9..98959fe764 100644 --- a/commons/src/test/java/com/vitorpamplona/amethyst/commons/SRGBTest.kt +++ b/commons/src/test/java/com/vitorpamplona/amethyst/commons/SRGBTest.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.commons import com.vitorpamplona.amethyst.commons.blurhash.SRGB -import junit.framework.TestCase.assertEquals +import org.junit.Assert.assertEquals import org.junit.Test import kotlin.math.round diff --git a/gradle.properties b/gradle.properties index 1a34c8cb1d..99f780b98a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,4 +24,7 @@ android.nonTransitiveRClass=true android.enableR8.fullMode=true android.nonFinalResIds=false -kotlin.daemon.jvmargs=-Xmx12g -XX:MaxMetaspaceSize=3g \ No newline at end of file +kotlin.daemon.jvmargs=-Xmx12g -XX:MaxMetaspaceSize=3g + +# because we use a custom jvmAndroid target +kotlin.mpp.applyDefaultHierarchyTemplate=false \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 01ae64a444..a376308724 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,10 +26,12 @@ jtorctl = "0.4.5.7" junit = "4.13.2" kotlin = "2.2.20" kotlinxCollectionsImmutable = "0.4.0" +kotlinxDatetime = "0.7.1" kotlinxSerialization = "1.9.0" kotlinxSerializationPlugin = "2.2.20" languageId = "17.0.6" lazysodiumAndroid = "5.2.0" +lazysodiumJava = "5.2.0" lifecycleRuntimeKtx = "2.9.3" lightcompressor = "1.3.3" markdown = "e1151c8" @@ -54,6 +56,7 @@ zxing = "3.5.3" zxingAndroidEmbedded = "4.3.0" windowCoreAndroid = "1.4.0" androidxCamera = "1.5.0" +androidxCollection = "1.5.0" kotlinStdlib = "2.2.10" kotlinTest = "2.2.10" core = "1.7.0" @@ -74,6 +77,7 @@ androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", versi androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation" } androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime" } +androidx-collection-jvm = { group = "androidx.collection", name = "collection-jvm", version.ref = "androidxCollection" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore" } androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } @@ -114,7 +118,10 @@ jna = { group = "net.java.dev.jna", name = "jna", version.ref = "jna" } jtorctl = { module = "info.guardianproject:jtorctl", version.ref = "jtorctl" } junit = { group = "junit", name = "junit", version.ref = "junit" } kotlinx-collections-immutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version.ref = "kotlinxCollectionsImmutable" } +kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" } +kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerialization" } kotlinx-serialization-cbor = { module = "org.jetbrains.kotlinx:kotlinx-serialization-cbor", version.ref = "kotlinxSerialization" } +lazysodium-java = { group = "com.goterl", name = "lazysodium-java", version.ref = "lazysodiumJava" } lazysodium-android = { group = "com.goterl", name = "lazysodium-android", version.ref = "lazysodiumAndroid" } markdown-commonmark = { group = "com.github.vitorpamplona.compose-richtext", name = "richtext-commonmark", version.ref = "markdown" } markdown-ui = { group = "com.github.vitorpamplona.compose-richtext", name = "richtext-ui", version.ref = "markdown" } diff --git a/quartz/build.gradle.kts b/quartz/build.gradle.kts index 423db6ce96..09a0b6f1bd 100644 --- a/quartz/build.gradle.kts +++ b/quartz/build.gradle.kts @@ -3,6 +3,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { alias(libs.plugins.kotlinMultiplatform) alias(libs.plugins.androidLibrary) + alias(libs.plugins.serialization) } android { @@ -44,6 +45,7 @@ android { kotlin { compilerOptions { freeCompilerArgs.add("-Xstring-concat=inline") + freeCompilerArgs.add("-Xexpect-actual-classes") } jvm { compilerOptions { @@ -70,12 +72,6 @@ kotlin { // https://developer.android.com/kotlin/multiplatform/migrate val xcfName = "quartz-kmpKit" - iosX64 { - binaries.framework { - baseName = xcfName - } - } - iosArm64 { binaries.framework { baseName = xcfName @@ -102,7 +98,17 @@ kotlin { // @Immutable and @Stable implementation(libs.androidx.compose.runtime) + // Bitcoin secp256k1 bindings api(libs.secp256k1.kmp.common) + + // Kotlin serialization for the times where we need the Json tree and performance is not that important. + implementation(libs.kotlinx.serialization.json) + + // in your shared module's dependencies block + implementation( libs.kotlinx.datetime) + + // immutable collections to avoid recomposition + implementation(libs.kotlinx.collections.immutable) } } @@ -112,25 +118,38 @@ kotlin { } } - jvmMain { + // Must be defined before androidMain and jvmMain + val jvmAndroid = create("jvmAndroid") { + dependsOn(commonMain.get()) + dependencies { - // Bitcoin secp256k1 bindings - api(libs.secp256k1.kmp.jni.jvm) - - // Performant Parser of JSONs into Events - api(libs.jackson.module.kotlin) - - // immutable collections to avoid recomposition - api(libs.kotlinx.collections.immutable) - - // Parses URLs from Text: - api(libs.url.detector) + // For LruCache + implementation(libs.androidx.collection.jvm) // Normalizes URLs api(libs.rfc3986.normalizer) + // Performant Parser of JSONs into Events + api(libs.jackson.module.kotlin) + + // Parses URLs from Text: + api(libs.url.detector) + // Websockets API implementation(libs.okhttp) + implementation(libs.okhttpCoroutines) + } + } + + jvmMain { + dependsOn(jvmAndroid) + dependencies { + // Bitcoin secp256k1 bindings + api(libs.secp256k1.kmp.jni.jvm) + + // LibSodium for ChaCha encryption (NIP-44) + implementation (libs.lazysodium.java) + implementation (libs.jna) } } @@ -142,6 +161,7 @@ kotlin { } androidMain { + dependsOn(jvmAndroid) dependencies { implementation(libs.androidx.core.ktx) @@ -154,21 +174,6 @@ kotlin { // LibSodium for ChaCha encryption (NIP-44) implementation ("com.goterl:lazysodium-android:5.2.0@aar") implementation ("net.java.dev.jna:jna:5.17.0@aar") - - // Performant Parser of JSONs into Events - api(libs.jackson.module.kotlin) - - // immutable collections to avoid recomposition - api(libs.kotlinx.collections.immutable) - - // Parses URLs from Text: - api(libs.url.detector) - - // Normalizes URLs - api(libs.rfc3986.normalizer) - - // Websockets API - implementation(libs.okhttp) } } @@ -189,13 +194,33 @@ kotlin { } iosMain { + dependsOn(commonMain.get()) dependencies { - // Add iOS-specific dependencies here. This a source set created by Kotlin Gradle - // Plugin (KGP) that each specific iOS target (e.g., iosX64) depends on as - // part of KMP’s default source set hierarchy. Note that this source set depends - // on common by default and will correctly pull the iOS artifacts of any - // KMP dependencies declared in commonMain. + } } + + val iosArm64Main by getting { + dependsOn(iosMain.get()) // iosArm64Main depends on iosMain + } + + val iosSimulatorArm64Main by getting { + dependsOn(iosMain.get()) // iosSimulatorArm64Main depends on iosMain + } + + iosTest { + dependsOn(commonTest.get()) + dependencies { + + } + } + + val iosArm64Test by getting { + dependsOn(iosTest.get()) // iosArm64Main depends on iosMain + } + + val iosSimulatorArm64Test by getting { + dependsOn(iosTest.get()) // iosSimulatorArm64Main depends on iosMain + } } } \ No newline at end of file diff --git a/quartz/src/androidInstrumentedTest/resources/relayDB.txt b/quartz/relayDB.txt similarity index 100% rename from quartz/src/androidInstrumentedTest/resources/relayDB.txt rename to quartz/relayDB.txt diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/LargeDBSignatureCheck.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/LargeDBSignatureCheck.kt index ed5257c58c..895159ce95 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/LargeDBSignatureCheck.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/LargeDBSignatureCheck.kt @@ -23,11 +23,11 @@ package com.vitorpamplona.quartz import androidx.test.ext.junit.runners.AndroidJUnit4 import com.fasterxml.jackson.module.kotlin.readValue import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper -import com.vitorpamplona.quartz.nip01Core.verify +import com.vitorpamplona.quartz.nip01Core.crypto.verify +import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertTrue import kotlinx.coroutines.runBlocking +import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import java.io.InputStreamReader @@ -41,7 +41,7 @@ class LargeDBSignatureCheck { val fullDBInputStream = javaClass.classLoader?.getResourceAsStream("nostr_vitor_short.json") val eventArray = - JsonMapper.mapper.readValue>( + JacksonMapper.mapper.readValue>( InputStreamReader(fullDBInputStream), ) as List @@ -61,7 +61,7 @@ class LargeDBSignatureCheck { val fullDBInputStream = javaClass.classLoader?.getResourceAsStream("nostr_vitor_startup_data.json") val eventArray = - JsonMapper.mapper.readValue>( + JacksonMapper.mapper.readValue>( GZIPInputStream(fullDBInputStream), ) as List diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/bloom/BloomFilter.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/bloom/BloomFilter.kt index 30c9da492a..5fd1adbb26 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/bloom/BloomFilter.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/bloom/BloomFilter.kt @@ -26,9 +26,9 @@ import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.crypto.Nip01 import com.vitorpamplona.quartz.utils.RandomInstance import com.vitorpamplona.quartz.utils.sha256.Sha256Hasher -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertFalse -import junit.framework.TestCase.assertTrue +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import java.math.BigInteger diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/EventSigCheck.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/EventSigCheck.kt index cb46c720d9..7b7cd67ee6 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/EventSigCheck.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/EventSigCheck.kt @@ -21,14 +21,19 @@ package com.vitorpamplona.quartz.nip01Core import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.vitorpamplona.quartz.EventFactory -import com.vitorpamplona.quartz.nip01Core.crypto.EventHasher -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper +import com.vitorpamplona.quartz.nip01Core.crypto.EventHasherSerializer +import com.vitorpamplona.quartz.nip01Core.crypto.checkSignature +import com.vitorpamplona.quartz.nip01Core.crypto.verifyId +import com.vitorpamplona.quartz.nip01Core.crypto.verifySignature +import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.EventMessage +import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.Message import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertTrue +import com.vitorpamplona.quartz.utils.EventFactory +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith @@ -59,11 +64,10 @@ class EventSigCheck { @Test fun testUnicode2028and2029ShouldNotBeEscaped() { - val msg = JsonMapper.mapper.readTree(payload1) - val event = JsonMapper.fromJson(msg[2]) + val msg = OptimizedJsonMapper.fromJsonTo(payload1) as EventMessage // Should pass - event.checkSignature() + msg.event.checkSignature() } @Test @@ -83,8 +87,8 @@ class EventSigCheck { sig = "6df6aeef98c21a0508a788cbe6a2a6825e5cc69e57dd843dc6e6d4ce2c28dd042947723fda3d8b24489305d86b1e81f9f66b390d6f7dabf9742cd3775e17e53f", ) - val old = EventHasher.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) - val new = EventHasher.fastMakeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) + val old = EventHasherSerializer.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) + val new = EventHasherSerializer.fastMakeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) assertEquals(old.toByteArray().joinToString(), new.joinToString()) assertTrue(event.verifySignature()) @@ -117,8 +121,8 @@ class EventSigCheck { sig = "e03c81ec2543e777583bfcf93c0d82d3055a47a541b1a961db010ed2390e56ddc59e4f891505672757b7ac0d52e891854fdd61f1a4e13b4e6aa563e94cb9368e", ) - val old = EventHasher.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) - val new = EventHasher.fastMakeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) + val old = EventHasherSerializer.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) + val new = EventHasherSerializer.fastMakeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) println(old) println(String(new)) @@ -149,8 +153,8 @@ class EventSigCheck { sig = "81d08765524bd8b774585a57c76d25b1d2c09eaa23efcb075226ba8b64f42e3d9d9403e5edf888e0e58702a24abc084259e21b97e24a275021c5e36186c65f0c", ) - val old = EventHasher.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) - val new = EventHasher.fastMakeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) + val old = EventHasherSerializer.makeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) + val new = EventHasherSerializer.fastMakeJsonForId(event.pubKey, event.createdAt, event.kind, event.tags, event.content) println(old) println(String(new)) diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/BasicTest.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/BasicTest.kt index 8aa2a7f3be..e125bec709 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/BasicTest.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/BasicTest.kt @@ -27,8 +27,8 @@ import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip22Comments.CommentEvent -import junit.framework.TestCase.assertEquals import org.junit.After +import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/ExpirationTest.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/ExpirationTest.kt index 9194df913b..add6ce20b2 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/ExpirationTest.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/ExpirationTest.kt @@ -28,9 +28,9 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip40Expiration.expiration import com.vitorpamplona.quartz.utils.TimeUtils -import junit.framework.TestCase.assertTrue import junit.framework.TestCase.fail import org.junit.After +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/LargeDBTests.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/LargeDBTests.kt index 8b4d1a2767..3d75a03e2e 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/LargeDBTests.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/LargeDBTests.kt @@ -22,13 +22,13 @@ package com.vitorpamplona.quartz.nip01Core.store.sqlite import android.content.Context import android.database.sqlite.SQLiteException -import android.util.Log import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.fasterxml.jackson.module.kotlin.readValue import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper import com.vitorpamplona.quartz.nip40Expiration.isExpired +import com.vitorpamplona.quartz.utils.Log import org.junit.After import org.junit.Before import org.junit.Test @@ -43,7 +43,7 @@ class LargeDBTests { // This file includes duplicates val fullDBInputStream = javaClass.classLoader?.getResourceAsStream("nostr_vitor_startup_data.json") - return JsonMapper.mapper.readValue>( + return JacksonMapper.mapper.readValue>( GZIPInputStream(fullDBInputStream), ) } diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OtsTest.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OtsTest.kt index 1a852eaea0..b61524f7a4 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OtsTest.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OtsTest.kt @@ -25,14 +25,20 @@ import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip03Timestamp.OtsEvent import com.vitorpamplona.quartz.nip03Timestamp.OtsResolver -import junit.framework.TestCase.assertEquals +import com.vitorpamplona.quartz.nip03Timestamp.okhttp.OkHttpOtsResolverBuilder import junit.framework.TestCase.assertNotNull import junit.framework.TestCase.fail import kotlinx.coroutines.runBlocking +import okhttp3.OkHttpClient +import org.junit.Assert.assertEquals import org.junit.Test class OtsTest { - val resolver = OtsResolver() + val okHttpClient = OkHttpClient.Builder().build() + val resolver: OtsResolver = + OkHttpOtsResolverBuilder { + okHttpClient + }.build() val otsEvent = "{\"content\":\"AE9wZW5UaW1lc3RhbXBzAABQcm9vZgC/ieLohOiSlAEIqCiiW0FlsU9lqK5f1A+cL6CGJ1Ah4V/A1yNJY/stUE3wECJz6ng/QxU5Z6xwaMx97qkI//AQqJv8bEMrGTplGWRv5qm4DgjxIHkcQqzpL0Fjr9VBAAijDe0IsQYpOhw1SIjZIgQa6i16CPEEZck7CvAIxR0AloJzCZoAg9/jDS75DI4uLWh0dHBzOi8vYWxpY2UuYnRjLmNhbGVuZGFyLm9wZW50aW1lc3RhbXBzLm9yZ//wEOwPtjIkKI1hmtv9t1kuxZcI8QRlyTsK8Ahl0wrCSggZzgCD3+MNLvkMjiwraHR0cHM6Ly9ib2IuYnRjLmNhbGVuZGFyLm9wZW50aW1lc3RhbXBzLm9yZ//wEE1dVGa8JCuf2ek0c5ybDKII8SCBoVz8Sal45Kd1O8STWIGJTcl5JPtAZBZitqk3BE9MqAjxBGXJOwrwCHoGVgAZi9q9AIPf4w0u+QyOKShodHRwczovL2Zpbm5leS5jYWxlbmRhci5ldGVybml0eXdhbGwuY29t8BAFZFXFYg7DJJ0OzjmJ0FKWCPEEZck7CvAI0M49IcBR5bf/AIPf4w0u+QyOIyJodHRwczovL2J0Yy5jYWxlbmRhci5jYXRhbGxheHkuY29tCPEgoE3IfYTmxxo4W/x/QYp/NGX6Wu93gSQkwbpjpOhZORcI8SDWLLurVQaXHdUuwivCfTfuxYCaq+AzypSGqLDAVocrEgjwIBfgjta16y13Gp4etQOCa9YiKEcM+/9AieG/vZolr3IDCPAgMR2zFCb384CEi8tVuI2fHgLT3I9zpe7oqJTzCcEqxWEI8SAJSdgeeosr7IxdOt8r7f0ipWc8FI6GAhgep8zSRgWikAjxIGxYmtCsC79Tx4z4YsT1WuMo+ycMkwhGQsQltF597cchCPAgCLrBf9vR1Aex6yY+vSkXAvLjMKdMqM/a1g8zNPwLeJcI8SBDCbTk4CczTuiIyZeUyYRVh31BZdjaSd2nU/pBQxu+6QjwIOwqE9/WqGC6CHH0i+tr7edvYX5PstSDf08KmnMqsqCoCPEgQIdEBg358vfek3Qjfyrgl51iCU6WUWmThsGLPDTcB0QI8SAX4dp64iI8pBx+zBqAQwUN6XgZ1cEfT8+2vha/9I1vzwjxWQEAAAAB8YJxvxJJth8OnxIV6UOXveIZAcJPTHcAkWgnucpuYqYAAAAAAP3///8CRhoMAAAAAAAWABTUUZK82uAvbU3vVyaaPIOddZBicwAAAAAAAAAAImog8ARCqgwACAjwIB9TcMDLhzgeS1Uw647lNvCfWECkkUvfrrOe6nay0sGdCAjwICYfs90sbPggoMICyOHGYbmOzop2L9mlnh4xqiBLY7yPCAjxINDiVWOBHnRmGJleQdB9myvJAJbNJ9kciZlTOkgJy89mCAjwIHfxqDLdwycj1Vtyth2CaSDdLQwiey9oV6Xov4stLpWNCAjxIGurJYpKJnKp9+y7MAdC+gXgHOiAu5P3RRUFW9l5hGaCCAjxICXqs9hdY0QMP/MNeqlt6s7xaIYtEXZ1CLvou5gaZNEICAjxIHdYxVeI76NXbT2zHcv6lw+v819Ooib7KWxc1GAsiX2fCAjwICPWdi3uBXOlIdmYi+V9C7wAqLyGE4DMoHD+GtvLizqiCAjwIOF2vENtWN5okEMMS+JSf1SGTY9yYP9j0JjXLbC1s+N1CAjxINWsgCtsPxhRNbe372k8/20WDbiL9e8934hGF256DvRECAjwII3mi+Li06j10ORxg0dYMkcsyGb115Jiqq1YEV3K/u+aCAgABYiWDXPXGQEDw9Qy\",\"created_at\":1707690688,\"id\":\"759f9da5846e936fab06766a524b36ba71c03bbc69ad0944fb8ee4bb1f3dd705\",\"kind\":1040,\"pubkey\":\"82fbb08c8ef45c4d71c88368d0ae805bc62fb92f166ab04a0b7a0c83d8cbc29a\",\"sig\":\"07c7896c8cbb97b5d7483097590c9d31b73f35c1ad9e752002bb5c1776cbd852e1d32704333d6930c9bc3e40f8b899a1f2e9f91cc3bf797d86acdecba7792576\",\"tags\":[[\"e\",\"a828a25b4165b14f65a8ae5fd40f9c2fa086275021e15fc0d7234963fb2d504d\"],[\"p\",\"595ca8eaace5899cb6ab7e2542bfc972136376f2eabc09287f1857eb8f167e53\"],[\"alt\",\"NIP-03 time stamp\"]]}" val otsEvent2 = "{\"content\":\"AE9wZW5UaW1lc3RhbXBzAABQcm9vZgC/ieLohOiSlAEIqGNPU2jhd4no+zg2ytDkuf5PIoivr8KHI8BL68aKGNbwENyCNtiEN98IzIZgEu3cl6YI//AQ6TkSRd3BTGhDHCK1KkJc+AjxIAHaizG++NNL3Vm13BJrIhT7Br6tEYpb0TVRGaadgiUMCPAgOSDREH9v1Y50UHu79LfC4Lcd9WklQJzRQpw+Unb/pyII8QRltDD58AgqrxfAVrLw7QCD3+MNLvkMji4taHR0cHM6Ly9hbGljZS5idGMuY2FsZW5kYXIub3BlbnRpbWVzdGFtcHMub3Jn//AQQMq/CLpGwY60nmddPS7OVgjxIDKxqd9nl+Mej41vP52Wd7gv7004r3n1rFGDObS8icRvCPAgH9TB/kwvXJEEw+h9Ce6fLaI3MORjtTEge0GbAefT6W4I8QRltDD58AhRcoU3gAo/swCD3+MNLvkMjiwraHR0cHM6Ly9ib2IuYnRjLmNhbGVuZGFyLm9wZW50aW1lc3RhbXBzLm9yZ//wECWtWsKo0uvSr8BYonjs3DEI8CBlsh2ng1Spl0K4oStYElGuMJsjd2uo5nXB+apo5A7ipwjxIM8oxynBwNA+QS/X7Ebtl1kyhFgfoOQioASNfCBzZ4gaCPEEZbQw+fAId6Yd5cw5gioAg9/jDS75DI4pKGh0dHBzOi8vZmlubmV5LmNhbGVuZGFyLmV0ZXJuaXR5d2FsbC5jb23wEJmPzXQbxv0AFTIyjTWjMskI8CAurbkrfrBtlinZXSDxj+m/oIkze57hGjTSxu1Xs87XYQjwIPk/LMD0zIgKoEE2dfeoYrrdHuO6dwmghTwUFajH2QzkCPEEZbQw+fAIE+Pq1/Wmdpj/AIPf4w0u+QyOIyJodHRwczovL2J0Yy5jYWxlbmRhci5jYXRhbGxheHkuY29tCPAgB2CbqkV7VpjRKIl3Ea6cBmB/EHcSN/YCgcc1E+mc07QI8CAfpkZ2Hh4Rukz3x4il3tZqQtlDlbna+I6so2t2YSEmMQjwIJOv32jbsMa2HJwpleRCKLEhgYOoHCSfpv1ZO0YNNNFsCPAgLMM7eFfCjokQfU4gdU5WpG/wBLkO9lDRF0GktL6ujt8I8SCRxJ0bC1PQ8qFmI/1jh8AS5d1/6VRJNMt1Hz41QmNr3QjwIBmgrKBF+OZ3y+XOMv2E7IZ4WwLr2u2H+ehsBfy7cPlICPEgm4ZMCSXzZVWu40d+zk2edaur6KOauo8X7V2KaFBR1VoI8SBKVVOiyq6IFqGn/15kLwk7L8upMAIZ0znjhYxYqSTQCQjwIMBD1twPZ33GxbwTiuOCeJPkoP++6R2wYpCii8UBTdgwCPAg84VkgMXwrt2xxRoeC1/6CtsFctki+w3m8Rs5/6g/IhEI8CCnzZQDhJyicX7bS7U8PMUObuC9Y4TXe+4THoXBMMXkxwjxIMZ0oAvshpcwowR3qPEDbwKZ6B4NPSU4Hz/+4PnD74gnCPAgIfLZEKqAvkMNXfakXoNq1UVqGSzL4Z86z5GzUfbvw8UI8SC8KoIeLvjd4vJ/xhNVphakPRd80YKeNkeYEuVH8k2EtAjwIPRtinLLxzt8iuw0XZtpTDzEstZOTNYVm+Bi3fEzdeIuCPFZAQAAAAE8vsasINN5DKon0KakX2HNdCB126ZLKXrw4PfvyEfqbwAAAAAA/f///wLPGw8AAAAAABYAFCvgxlh6msa4ZOtgvlc5KiZCx7IvAAAAAAAAAAAiaiDwBKygDAAICPEgB/2DJ3s6gMky/PceGZocTFRXjZUiCCAhHGYwQk/8yrUICPEgDuSd6+PJHUMuEHyLcKFxw7xfvRHRfInjkV3/Zy3BxqAICPEgZDgQ+4VXzlOIkGoO8EVxDgs2cWaeh4EEiaqa/y50gKAICPAgFI+zIuYcMF69GmPQVsXa9oy8eng7MeRZdIxArQyeX3oICPEgX5HYIuImpiSTEapgEssEW4l+W+4aRfNCG3pZf7z0hCoICPEgPkAbOSjFdtS4NT7MXgMYVQoQhI1JZtdFxUu4J3NTt7IICPEguW3qyuyGjctu5d9rM9P9ZCs/ZK4vAc+z21b9ygklgWAICPEgu4e2645xtvGhI1Zzuiv23vRhwE8uC9vj1TAgNg/C8UcICPAgwoQX8X0nY4HoQLRsJ0z8JCWQDzRh2iL2QXEb8z3gbjIICPAgzTwlPRtStsLJWhz3Q/0l8tMnrPSHVuh+zCiGk95dW2MICPAgGcBEuYZyzFNapHOfnJ9Q515QzO2VbIRhlVI0vIhd4jwICPAgidRMoM2pA+KmVJenVrLcbollsbUg9lL9bmv1C1dSxswICPAgZinGakwhbHdanTaRJeBkEUlbhfNokvj8b5KneyG+wzIICAAFiJYNc9cZAQOtwTI=\",\"created_at\":1706324334,\"id\":\"2ad074ddb7724eb13b4244b49cf2321b1057f37fdf8ce102e6329b839cf763a9\",\"kind\":1040,\"pubkey\":\"82fbb08c8ef45c4d71c88368d0ae805bc62fb92f166ab04a0b7a0c83d8cbc29a\",\"sig\":\"ad7274bb32ba9e9cfdbd52f4887e8a2fda1047c75a7185b2ab7ff254ebac14ed48a2b60737494d655e24c9400eeeec7e29293a77bfcaafaecd94b350c9a2c22b\",\"tags\":[[\"e\",\"a8634f5368e17789e8fb3836cad0e4b9fe4f2288afafc28723c04bebc68a18d6\"],[\"p\",\"c31e22c3715c1bde5608b7e0d04904f22f5fc453ba1806d21c9f2382e1e58c6c\"],[\"alt\",\"NIP-03 time stamp\"]]}" @@ -41,57 +47,61 @@ class OtsTest { val otsEvent2Digest = "a8634f5368e17789e8fb3836cad0e4b9fe4f2288afafc28723c04bebc68a18d6" @Test - fun verifyNostrEvent() { - val ots = Event.fromJson(otsEvent) as OtsEvent - println(resolver.info(ots.otsByteArray())) - assertEquals(1707688818L, ots.verify(resolver)) - } + fun verifyNostrEvent() = + runBlocking { + val ots = Event.fromJson(otsEvent) as OtsEvent + println(resolver.info(ots.otsByteArray())) + assertEquals(1707688818L, ots.verify(resolver)) + } @Test - fun verifyNostrEvent2() { - val ots = Event.fromJson(otsEvent2) as OtsEvent - println(resolver.info(ots.otsByteArray())) - assertEquals(1706322179L, ots.verify(resolver)) - } + fun verifyNostrEvent2() = + runBlocking { + val ots = Event.fromJson(otsEvent2) as OtsEvent + println(resolver.info(ots.otsByteArray())) + assertEquals(1706322179L, ots.verify(resolver)) + } @Test - fun verifyNostrPendingEvent() { - val ots = Event.fromJson(otsPendingEvent) as OtsEvent - println(resolver.info(ots.otsByteArray())) - assertEquals(null, ots.verify(resolver)) + fun verifyNostrPendingEvent() = + runBlocking { + val ots = Event.fromJson(otsPendingEvent) as OtsEvent + println(resolver.info(ots.otsByteArray())) + assertEquals(null, ots.verify(resolver)) - val eventId = - ots.digestEventId() ?: run { + val eventId = ots.digestEventId() + + if (eventId == null) { fail("Should not be null") - return + } else { + val upgraded = OtsEvent.upgrade(ots.otsByteArray(), eventId, resolver) + + assertNotNull(upgraded) + + val signer = NostrSignerInternal(KeyPair()) + + val newOts = runBlocking { signer.sign(OtsEvent.build(eventId, upgraded!!)) } + + println(newOts.toJson()) + println(resolver.info(newOts.otsByteArray())) + + assertEquals(1708879025L, newOts.verify(resolver)) } - - val upgraded = OtsEvent.upgrade(ots.otsByteArray(), eventId, resolver) - - assertNotNull(upgraded) - - val signer = NostrSignerInternal(KeyPair()) - - val newOts = runBlocking { signer.sign(OtsEvent.build(eventId, upgraded!!)) } - - println(newOts.toJson()) - println(resolver.info(newOts.otsByteArray())) - - assertEquals(1708879025L, newOts.verify(resolver)) - } + } @Test - fun createOTSEventAndVerify() { - val signer = NostrSignerInternal(KeyPair()) + fun createOTSEventAndVerify() = + runBlocking { + val signer = NostrSignerInternal(KeyPair()) - val ots = - runBlocking { - signer.sign(OtsEvent.build(otsEvent2Digest, OtsEvent.stamp(otsEvent2Digest, resolver))) - } + val ots = + runBlocking { + signer.sign(OtsEvent.build(otsEvent2Digest, OtsEvent.stamp(otsEvent2Digest, resolver))) + } - println(ots.toJson()) - println(resolver.info(ots.otsByteArray())) + println(ots.toJson()) + println(resolver.info(ots.otsByteArray())) - assertEquals(null, ots.verify(resolver)) - } + assertEquals(null, ots.verify(resolver)) + } } diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip04Dm/EncryptionTest.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip04Dm/EncryptionTest.kt index 5da5cc912d..2ed0e14d70 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip04Dm/EncryptionTest.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip04Dm/EncryptionTest.kt @@ -25,8 +25,8 @@ import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.crypto.Nip01 import com.vitorpamplona.quartz.nip04Dm.crypto.EncryptedInfo import com.vitorpamplona.quartz.nip04Dm.crypto.Encryption -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertTrue +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Test class EncryptionTest { diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip32SeedDerivationTest.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip32SeedDerivationTest.kt index 15f2ef3608..bf184325ed 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip32SeedDerivationTest.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip32SeedDerivationTest.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.quartz.nip06KeyDerivation import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.nip01Core.core.toHexKey -import junit.framework.TestCase.assertEquals +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39KeyPathTest.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39KeyPathTest.kt index 060a094806..225b0a347a 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39KeyPathTest.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39KeyPathTest.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.quartz.nip06KeyDerivation import androidx.test.ext.junit.runners.AndroidJUnit4 -import junit.framework.TestCase.assertEquals +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39MnemonicsTest.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39MnemonicsTest.kt index 7b0dd25bdd..5915b9f789 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39MnemonicsTest.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39MnemonicsTest.kt @@ -25,9 +25,9 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.utils.Hex import com.vitorpamplona.quartz.utils.RandomInstance -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertTrue import junit.framework.TestCase.fail +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Nip06Test.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Nip06Test.kt index 1cdc0f42d0..834f81ed0d 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Nip06Test.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Nip06Test.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.quartz.nip06KeyDerivation import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.nip01Core.core.toHexKey -import junit.framework.TestCase.assertEquals +import org.junit.Assert.assertEquals import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip10Notes/CitationTests.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip10Notes/CitationTests.kt index eee4cb2933..5df96e2e60 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip10Notes/CitationTests.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip10Notes/CitationTests.kt @@ -21,15 +21,15 @@ package com.vitorpamplona.quartz.nip10Notes import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.vitorpamplona.quartz.nip01Core.crypto.verify import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEventIds import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.taggedUserIds import com.vitorpamplona.quartz.nip01Core.tags.people.taggedUsers -import com.vitorpamplona.quartz.nip01Core.verify -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertTrue +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip10Notes/ThreadingTests.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip10Notes/ThreadingTests.kt index 3e10f561dc..7b37ad3f8b 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip10Notes/ThreadingTests.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip10Notes/ThreadingTests.kt @@ -25,7 +25,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.taggedUsers import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag -import junit.framework.TestCase.assertEquals +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip17Dm/AESGCMTest.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip17Dm/AESGCMTest.kt index 94cae91122..66ef3ac870 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip17Dm/AESGCMTest.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip17Dm/AESGCMTest.kt @@ -22,8 +22,8 @@ package com.vitorpamplona.quartz.nip17Dm import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray -import com.vitorpamplona.quartz.nip17Dm.files.encryption.AESGCM -import junit.framework.TestCase.assertEquals +import com.vitorpamplona.quartz.utils.ciphers.AESGCM +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith @@ -32,7 +32,11 @@ class AESGCMTest { val decryptionNonce = "01e77c94bd5aba3e3cbb69594e7ba07c" val decryptionKey = "c128ecffab90ee7810e3df08e7fb2cc39a8d40f24201f48b2b36e23b34ac50ee" - val cipher = AESGCM(decryptionKey.hexToByteArray(), decryptionNonce.toByteArray(Charsets.UTF_8)) + val cipher = + AESGCM( + decryptionKey.hexToByteArray(), + decryptionNonce.toByteArray(Charsets.UTF_8), + ) @Test fun encryptDecrypt() { diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/NIP19EmbedTests.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/NIP19EmbedTests.kt index f6c574544d..eaa681d547 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/NIP19EmbedTests.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/NIP19EmbedTests.kt @@ -24,15 +24,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.experimental.medical.FhirResourceEvent import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair +import com.vitorpamplona.quartz.nip01Core.crypto.verify import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal -import com.vitorpamplona.quartz.nip01Core.verify import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip19Bech32.entities.NEmbed import com.vitorpamplona.quartz.utils.Hex -import junit.framework.TestCase.assertEquals import junit.framework.TestCase.assertNotNull import junit.framework.TestCase.assertTrue import kotlinx.coroutines.runBlocking +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip22Comments/GeolocatedComments.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip22Comments/GeolocatedComments.kt index 6f0707638d..2d98360b77 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip22Comments/GeolocatedComments.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip22Comments/GeolocatedComments.kt @@ -23,13 +23,13 @@ package com.vitorpamplona.quartz.nip22Comments import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair +import com.vitorpamplona.quartz.nip01Core.crypto.verify import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync -import com.vitorpamplona.quartz.nip01Core.verify import com.vitorpamplona.quartz.nip73ExternalIds.location.GeohashId import com.vitorpamplona.quartz.nip73ExternalIds.location.geohashedScope -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertFalse -import junit.framework.TestCase.assertTrue +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v2Test.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v2Test.kt index 0d489fc94e..8755a39ecb 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v2Test.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v2Test.kt @@ -21,28 +21,27 @@ package com.vitorpamplona.quartz.nip44Encryption import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.crypto.Nip01 import com.vitorpamplona.quartz.utils.RandomInstance import com.vitorpamplona.quartz.utils.sha256.sha256 -import junit.framework.TestCase.assertEquals import junit.framework.TestCase.assertNotNull import junit.framework.TestCase.assertNull import junit.framework.TestCase.fail +import kotlinx.serialization.json.decodeFromStream +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class Nip44v2Test { private val vectors: VectorFile = - jacksonObjectMapper() - .readValue( - javaClass.classLoader?.getResourceAsStream("nip44.vectors.json"), - VectorFile::class.java, - ) + JsonMapper.jsonInstance.decodeFromStream( + javaClass.classLoader.getResourceAsStream("nip44.vectors.json"), + ) private val nip44v2 = Nip44v2() diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip44Encryption/TestPackageClasses.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip44Encryption/TestPackageClasses.kt index 4262d36bea..af296cc4c8 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip44Encryption/TestPackageClasses.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip44Encryption/TestPackageClasses.kt @@ -20,71 +20,82 @@ */ package com.vitorpamplona.quartz.nip44Encryption -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +@Serializable data class VectorFile( val v2: V2? = V2(), ) +@Serializable data class V2( val valid: Valid? = Valid(), val invalid: Invalid? = Invalid(), ) +@Serializable data class Valid( - @field:JsonProperty("get_conversation_key") val getConversationKey: ArrayList = arrayListOf(), - @field:JsonProperty("get_message_keys") val getMessageKeys: GetMessageKeys? = GetMessageKeys(), - @field:JsonProperty("calc_padded_len") val calcPaddedLen: ArrayList> = arrayListOf(), - @field:JsonProperty("encrypt_decrypt") val encryptDecrypt: ArrayList = arrayListOf(), - @field:JsonProperty("encrypt_decrypt_long_msg") + @SerialName("get_conversation_key") val getConversationKey: ArrayList = arrayListOf(), + @SerialName("get_message_keys") val getMessageKeys: GetMessageKeys? = GetMessageKeys(), + @SerialName("calc_padded_len") val calcPaddedLen: ArrayList> = arrayListOf(), + @SerialName("encrypt_decrypt") val encryptDecrypt: ArrayList = arrayListOf(), + @SerialName("encrypt_decrypt_long_msg") val encryptDecryptLongMsg: ArrayList = arrayListOf(), ) +@Serializable data class Invalid( - @field:JsonProperty("encrypt_msg_lengths") val encryptMsgLengths: ArrayList = arrayListOf(), - @field:JsonProperty("get_conversation_key") val getConversationKey: ArrayList = arrayListOf(), - @field:JsonProperty("decrypt") val decrypt: ArrayList = arrayListOf(), + @SerialName("encrypt_msg_lengths") val encryptMsgLengths: ArrayList = arrayListOf(), + @SerialName("get_conversation_key") val getConversationKey: ArrayList = arrayListOf(), + @SerialName("decrypt") val decrypt: ArrayList = arrayListOf(), ) +@Serializable data class GetConversationKey( val sec1: String? = null, val pub2: String? = null, val note: String? = null, - @field:JsonProperty("conversation_key") val conversationKey: String? = null, + @SerialName("conversation_key") val conversationKey: String? = null, ) +@Serializable data class GetMessageKeys( - @field:JsonProperty("conversation_key") val conversationKey: String? = null, + @SerialName("conversation_key") val conversationKey: String? = null, val keys: ArrayList = arrayListOf(), ) +@Serializable data class Keys( - @field:JsonProperty("nonce") val nonce: String? = null, - @field:JsonProperty("chacha_key") val chachaKey: String? = null, - @field:JsonProperty("chacha_nonce") val chachaNonce: String? = null, - @field:JsonProperty("hmac_key") val hmacKey: String? = null, + @SerialName("nonce") val nonce: String? = null, + @SerialName("chacha_key") val chachaKey: String? = null, + @SerialName("chacha_nonce") val chachaNonce: String? = null, + @SerialName("hmac_key") val hmacKey: String? = null, ) +@Serializable data class EncryptDecrypt( val sec1: String? = null, val sec2: String? = null, - @field:JsonProperty("conversation_key") val conversationKey: String? = null, + @SerialName("conversation_key") val conversationKey: String? = null, val nonce: String? = null, val plaintext: String? = null, val payload: String? = null, ) +@Serializable data class EncryptDecryptLongMsg( - @field:JsonProperty("conversation_key") val conversationKey: String? = null, + @SerialName("conversation_key") val conversationKey: String? = null, val nonce: String? = null, val pattern: String? = null, val repeat: Int? = null, - @field:JsonProperty("plaintext_sha256") val plaintextSha256: String? = null, - @field:JsonProperty("payload_sha256") val payloadSha256: String? = null, + @SerialName("plaintext_sha256") val plaintextSha256: String? = null, + @SerialName("payload_sha256") val payloadSha256: String? = null, ) +@Serializable data class Decrypt( - @field:JsonProperty("conversation_key") val conversationKey: String? = null, + @SerialName("conversation_key") val conversationKey: String? = null, val nonce: String? = null, val plaintext: String? = null, val payload: String? = null, diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/Nip46Test.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/Nip46Test.kt index 61794b0964..720b47e1a1 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/Nip46Test.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/Nip46Test.kt @@ -25,11 +25,10 @@ import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal -import com.vitorpamplona.quartz.nip02FollowList.ReadWrite import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.utils.TimeUtils -import junit.framework.TestCase.assertEquals import kotlinx.coroutines.runBlocking +import org.junit.Assert.assertEquals import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/NIP49Test.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/NIP49Test.kt index 514cf3e2e2..dca389061c 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/NIP49Test.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/NIP49Test.kt @@ -22,9 +22,9 @@ package com.vitorpamplona.quartz.nip49PrivKeyEnc import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.nip01Core.core.toHexKey -import junit.framework.TestCase.assertEquals import junit.framework.TestCase.assertNotNull import junit.framework.TestCase.fail +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith @@ -60,11 +60,11 @@ public class NIP49Test { TEST_CASE, )!! - assertEquals(2, data.version) - assertEquals(16, data.logn) + assertEquals(2.toByte(), data.version) + assertEquals(16.toByte(), data.logn) assertEquals("52d7c3f8580e7b41953381e5bc49646b", data.salt.toHexKey()) assertEquals("c33f02a7dcaac8bdd8da23cd449783240b6ebc12edeea7bf", data.nonce.toHexKey()) - assertEquals(0, data.keySecurity) + assertEquals(0.toByte(), data.keySecurity) assertEquals("b8e8803440de7b3e9519c3e734cb2ac9a211ea2dc52312e5117a11a3022d813ab438719ca0b504a1193be510c3aee776", data.encryptedKey.toHexKey()) } diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapTests.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapTests.kt index 35f720ff30..c121ff9e77 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapTests.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapTests.kt @@ -22,9 +22,9 @@ package com.vitorpamplona.quartz.nip57Zaps import androidx.test.ext.junit.runners.AndroidJUnit4 import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip57Zaps.PrivateZapEncryption.Companion.createEncryptionPrivateKey @@ -40,7 +40,7 @@ class PrivateZapTests { @Test fun testPollZap() { val poll = - JsonMapper.fromJson( + OptimizedJsonMapper.fromJson( """{ "content": "New poll \n\n #zappoll", "created_at": 1682440713, diff --git a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip59GiftWraps/GiftWrapEventTest.kt b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip59GiftWraps/GiftWrapEventTest.kt index aa21965ee2..2c3cc1d4af 100644 --- a/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip59GiftWraps/GiftWrapEventTest.kt +++ b/quartz/src/androidInstrumentedTest/kotlin/com/vitorpamplona/quartz/nip59GiftWraps/GiftWrapEventTest.kt @@ -21,11 +21,11 @@ package com.vitorpamplona.quartz.nip59GiftWraps import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.vitorpamplona.quartz.nip01Core.checkSignature import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair +import com.vitorpamplona.quartz.nip01Core.crypto.checkSignature import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser @@ -619,16 +619,16 @@ class GiftWrapEventTest { json: String, privateKey: HexKey, ): Event { - val pkBytes = NostrSignerInternal(KeyPair(privateKey.hexToByteArray())) + val signer = NostrSignerInternal(KeyPair(privateKey.hexToByteArray())) val wrap = Event.fromJson(json) as GiftWrapEvent wrap.checkSignature() - assertEquals(pkBytes.pubKey, wrap.recipientPubKey()) + assertEquals(signer.pubKey, wrap.recipientPubKey()) - val event = wrap.unwrapThrowing(pkBytes) + val event = wrap.unwrapThrowing(signer) return if (event is SealedRumorEvent) { - event.unsealThrowing(pkBytes) + event.unsealThrowing(signer) } else { println(event.toJson()) fail("Event is not a Sealed Rumor") diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/Address.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.kt similarity index 59% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/Address.kt rename to quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.kt index 0f24ffd4fc..92eabead1c 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/Address.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.kt @@ -18,48 +18,42 @@ * 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.quartz.nip01Core.tags.addressables +package com.vitorpamplona.quartz.nip01Core.core import android.os.Parcel import android.os.Parcelable -import android.util.Log -import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.Kind -import com.vitorpamplona.quartz.nip19Bech32.Nip19Parser -import com.vitorpamplona.quartz.nip19Bech32.entities.NAddress -import com.vitorpamplona.quartz.utils.Hex import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.pointerSizeInBytes -data class Address( - val kind: Kind, - val pubKeyHex: HexKey, - val dTag: String = "", +actual data class Address actual constructor( + actual val kind: Kind, + actual val pubKeyHex: HexKey, + actual val dTag: String, ) : Comparable
, Parcelable { - fun toValue() = assemble(kind, pubKeyHex, dTag) + actual fun toValue() = assemble(kind, pubKeyHex, dTag) - fun countMemory(): Int = + actual fun countMemory(): Int = 3 * pointerSizeInBytes + 8 + // kind pubKeyHex.bytesUsedInMemory() + dTag.bytesUsedInMemory() - override fun compareTo(other: Address): Int { + actual override fun compareTo(other: Address): Int { val result = kind.compareTo(other.kind) - if (result == 0) { + return if (result == 0) { val result2 = pubKeyHex.compareTo(other.pubKeyHex) if (result2 == 0) { - return dTag.compareTo(other.dTag) + dTag.compareTo(other.dTag) } else { - return result2 + result2 } } else { - return result + result } } - companion object { + actual companion object { // ----------- // Manual Parcelable implementation to avoid issues between kmp and the parcelize plugin // ----------- @@ -73,40 +67,15 @@ data class Address( override fun newArray(size: Int): Array = arrayOfNulls(size) } - fun assemble( + actual fun assemble( kind: Int, pubKeyHex: HexKey, - dTag: String = "", - ) = "$kind:$pubKeyHex:$dTag" + dTag: String, + ) = AddressSerializer.assemble(kind, pubKeyHex, dTag) - @JvmStatic - fun parse(addressId: String): Address? { - if (addressId.isBlank()) return null - return try { - val parts = addressId.split(":", limit = 3) - if (parts.size > 2 && parts[1].length == 64 && Hex.isHex(parts[1])) { - Address(parts[0].toInt(), parts[1], parts.getOrNull(2) ?: "") - } else { - if (addressId.startsWith("naddr1")) { - val addr = Nip19Parser.uriToRoute(addressId)?.entity - if (addr is NAddress) { - addr.address() - } else { - Log.w("AddressableId", "Error parsing. naddr1 seems invalid: $addressId") - null - } - } else { - Log.w("AddressableId", "Error parsing. Not a valid address: $addressId") - null - } - } - } catch (t: Throwable) { - Log.e("AddressableId", "Error parsing: $addressId: ${t.message}", t) - null - } - } + actual fun parse(addressId: String) = AddressSerializer.parse(addressId) - fun isOfKind( + actual fun isOfKind( addressId: String, kind: String, ) = addressId.startsWith(kind) && addressId[kind.length] == ':' diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasher.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasher.kt deleted file mode 100644 index 46af39a314..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasher.kt +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip01Core.crypto - -import com.fasterxml.jackson.core.JsonEncoding -import com.fasterxml.jackson.core.JsonGenerator -import com.fasterxml.jackson.core.JsonProcessingException -import com.fasterxml.jackson.core.util.BufferRecycler -import com.fasterxml.jackson.core.util.ByteArrayBuilder -import com.fasterxml.jackson.databind.JsonMappingException -import com.fasterxml.jackson.databind.node.ArrayNode -import com.fasterxml.jackson.databind.node.JsonNodeFactory -import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.toHexKey -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper -import com.vitorpamplona.quartz.utils.Hex -import com.vitorpamplona.quartz.utils.sha256.sha256 -import java.io.IOException - -class EventHasher { - companion object { - fun makeJsonObjectForId( - pubKey: HexKey, - createdAt: Long, - kind: Int, - tags: Array>, - content: String, - ): ArrayNode { - val factory = JsonNodeFactory.instance - return factory.arrayNode(6).apply { - add(0) - add(pubKey) - add(createdAt) - add(kind) - add( - factory.arrayNode(tags.size).apply { - tags.forEach { tag -> - add( - factory.arrayNode(tag.size).apply { tag.forEach { add(it) } }, - ) - } - }, - ) - add(content) - } - } - - fun makeJsonForId( - pubKey: HexKey, - createdAt: Long, - kind: Int, - tags: Array>, - content: String, - ): String = JsonMapper.toJson(makeJsonObjectForId(pubKey, createdAt, kind, tags, content)) - - fun fastMakeJsonForId( - pubKey: HexKey, - createdAt: Long, - kind: Int, - tags: Array>, - content: String, - ): ByteArray { - val br: BufferRecycler = JsonMapper.mapper.factory._getBufferRecycler() - try { - ByteArrayBuilder(br).use { bb -> - val generator = JsonMapper.mapper.createGenerator(bb, JsonEncoding.UTF8) - generator.enable(JsonGenerator.Feature.COMBINE_UNICODE_SURROGATES_IN_UTF8) - generator.use { - it.writeStartArray() - it.writeNumber(0) - it.writeString(pubKey) - it.writeNumber(createdAt) - it.writeNumber(kind) - it.writeStartArray() - tags.forEach { tag -> - it.writeStartArray() - tag.forEach { value -> - it.writeString(value) - } - it.writeEndArray() - } - it.writeEndArray() - it.writeString(content) - it.writeEndArray() - } - - val result = bb.toByteArray() - bb.release() - return result - } - } catch (e: JsonProcessingException) { - throw e - } catch (e: IOException) { - // shouldn't really happen, but is declared as possibility so: - throw JsonMappingException.fromUnexpectedIOE(e) - } finally { - br.releaseToPool() - } - } - - fun hashIdBytes( - pubKey: HexKey, - createdAt: Long, - kind: Int, - tags: Array>, - content: String, - ): ByteArray = sha256(fastMakeJsonForId(pubKey, createdAt, kind, tags, content)) - - fun hashId(serializedJsonAsBytes: ByteArray): String = sha256(serializedJsonAsBytes).toHexKey() - - fun hashId( - pubKey: HexKey, - createdAt: Long, - kind: Int, - tags: Array>, - content: String, - ): String = hashIdBytes(pubKey, createdAt, kind, tags, content).toHexKey() - - fun hashIdEquals( - id: HexKey, - pubKey: HexKey, - createdAt: Long, - kind: Int, - tags: Array>, - content: String, - ): Boolean { - val outId = hashIdBytes(pubKey, createdAt, kind, tags, content) - return Hex.isEqual(id, outId) - } - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JsonMapper.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JsonMapper.kt deleted file mode 100644 index ea75d82bf5..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JsonMapper.kt +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip01Core.jackson - -import com.fasterxml.jackson.core.json.JsonReadFeature -import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.module.SimpleModule -import com.fasterxml.jackson.databind.node.ArrayNode -import com.fasterxml.jackson.databind.node.ObjectNode -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerMessage -import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequest -import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse -import com.vitorpamplona.quartz.nip47WalletConnect.Request -import com.vitorpamplona.quartz.nip47WalletConnect.RequestDeserializer -import com.vitorpamplona.quartz.nip47WalletConnect.Response -import com.vitorpamplona.quartz.nip47WalletConnect.ResponseDeserializer -import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult -import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResultJsonDeserializer -import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResultJsonSerializer -import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.Permission -import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.PermissionDeserializer -import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.PermissionSerializer -import com.vitorpamplona.quartz.nip59Giftwrap.rumors.Rumor -import com.vitorpamplona.quartz.nip59Giftwrap.rumors.RumorDeserializer -import com.vitorpamplona.quartz.nip59Giftwrap.rumors.RumorSerializer - -class JsonMapper { - companion object { - val defaultPrettyPrinter = InliningTagArrayPrettyPrinter() - - val mapper = - jacksonObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature()) - .setDefaultPrettyPrinter(defaultPrettyPrinter) - .registerModule( - SimpleModule() - .addSerializer(Event::class.java, EventSerializer()) - .addDeserializer(Event::class.java, EventDeserializer()) - .addSerializer(Rumor::class.java, RumorSerializer()) - .addDeserializer(Rumor::class.java, RumorDeserializer()) - .addDeserializer(Response::class.java, ResponseDeserializer()) - .addDeserializer(Request::class.java, RequestDeserializer()) - .addDeserializer(BunkerMessage::class.java, BunkerMessage.BunkerMessageDeserializer()) - .addSerializer(BunkerRequest::class.java, BunkerRequest.BunkerRequestSerializer()) - .addDeserializer(BunkerRequest::class.java, BunkerRequest.BunkerRequestDeserializer()) - .addSerializer(BunkerResponse::class.java, BunkerResponse.BunkerResponseSerializer()) - .addDeserializer(BunkerResponse::class.java, BunkerResponse.BunkerResponseDeserializer()) - .addDeserializer(Permission::class.java, PermissionDeserializer()) - .addSerializer(Permission::class.java, PermissionSerializer()) - .addDeserializer(IntentResult::class.java, IntentResultJsonDeserializer()) - .addSerializer(IntentResult::class.java, IntentResultJsonSerializer()) - .addDeserializer(Array>::class.java, TagArrayDeserializer()) - .addSerializer(Array>::class.java, TagArraySerializer()), - ) - - fun fromJson(json: String): Event = mapper.readValue(json, Event::class.java) - - fun fromJson(json: JsonNode): Event = EventManualDeserializer.fromJson(json) - - fun toJson(event: Event): String = mapper.writeValueAsString(event) - - fun toJson(event: ArrayNode?): String = mapper.writeValueAsString(event) - - fun toJson(event: ObjectNode?): String = mapper.writeValueAsString(event) - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CountCmd.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CountCmd.kt deleted file mode 100644 index 7c9c7cc4e6..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CountCmd.kt +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip01Core.relay.commands.toRelay - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.node.ObjectNode -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper -import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter -import com.vitorpamplona.quartz.nip01Core.relay.filters.FilterDeserializer -import com.vitorpamplona.quartz.utils.joinToStringLimited - -class CountCmd( - val subscriptionId: String, - val filters: List, -) : Command { - companion object { - const val LABEL = "COUNT" - - @JvmStatic - fun toJson( - requestId: String, - filters: List, - limit: Int = 19, - ): String = - filters.joinToStringLimited( - separator = ",", - limit = limit, - prefix = """["COUNT","$requestId",""", - postfix = "]", - ) { - it.toJson() - } - - @JvmStatic - fun parse(msgArray: JsonNode): CountCmd { - val filters = mutableListOf() - - for (i in 2 until msgArray.size()) { - val json = JsonMapper.mapper.readTree(msgArray.get(i).asText()) - if (json is ObjectNode) { - filters.add(FilterDeserializer.fromJson(json)) - } - } - - return CountCmd(msgArray.get(1).asText(), filters) - } - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/ReqCmd.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/ReqCmd.kt deleted file mode 100644 index b613627947..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/ReqCmd.kt +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip01Core.relay.commands.toRelay - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.node.ObjectNode -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper -import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter -import com.vitorpamplona.quartz.nip01Core.relay.filters.FilterDeserializer -import com.vitorpamplona.quartz.utils.joinToStringLimited - -class ReqCmd( - val subscriptionId: String, - val filters: List, -) : com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.Command { - companion object { - const val LABEL = "REQ" - - @JvmStatic - fun toJson( - requestId: String, - filters: List, - limit: Int = 19, - ): String = - filters.joinToStringLimited( - separator = ",", - limit = limit, - prefix = """["REQ","$requestId",""", - postfix = "]", - ) { - it.toJson() - } - - @JvmStatic - fun parse(msgArray: JsonNode): ReqCmd { - val filters = mutableListOf() - - for (i in 2 until msgArray.size()) { - val json = JsonMapper.mapper.readTree(msgArray.get(i).asText()) - if (json is ObjectNode) { - filters.add(FilterDeserializer.fromJson(json)) - } - } - - return ReqCmd( - msgArray.get(1).asText(), - filters, - ) - } - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/ToRelayParser.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/ToRelayParser.kt deleted file mode 100644 index 1f0e558793..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/ToRelayParser.kt +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip01Core.relay.commands.toRelay - -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper - -class ToRelayParser { - fun parse(newMessage: String): Command? { - val msgArray = JsonMapper.mapper.readTree(newMessage) - val type = msgArray.get(0).asText() - return when (type) { - AuthCmd.LABEL -> AuthCmd.parse(msgArray) - CloseCmd.LABEL -> CloseCmd.parse(msgArray) - CountCmd.LABEL -> CountCmd.parse(msgArray) - EventCmd.LABEL -> EventCmd.parse(msgArray) - ReqCmd.LABEL -> ReqCmd.parse(msgArray) - else -> null - } - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterSerializer.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterSerializer.kt deleted file mode 100644 index 8756646402..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterSerializer.kt +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip01Core.relay.filters - -import com.fasterxml.jackson.databind.node.JsonNodeFactory -import com.fasterxml.jackson.databind.node.ObjectNode -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper - -object FilterSerializer { - fun toJsonObject( - ids: List? = null, - authors: List? = null, - kinds: List? = null, - tags: Map>? = null, - since: Long? = null, - until: Long? = null, - limit: Int? = null, - search: String? = null, - ): ObjectNode { - val factory = JsonNodeFactory.instance - 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? = null, - authors: List? = null, - kinds: List? = null, - tags: Map>? = null, - since: Long? = null, - until: Long? = null, - limit: Int? = null, - search: String? = null, - ): String = - JsonMapper.mapper.writeValueAsString( - toJsonObject( - ids, - authors, - kinds, - tags, - since, - until, - limit, - search, - ), - ) -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/EventIndexesModule.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/EventIndexesModule.kt index d1a2e2436e..0bb2b22c2b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/EventIndexesModule.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/EventIndexesModule.kt @@ -22,14 +22,13 @@ package com.vitorpamplona.quartz.nip01Core.store.sqlite import android.database.Cursor import android.database.sqlite.SQLiteDatabase -import com.fasterxml.jackson.module.kotlin.readValue -import com.vitorpamplona.quartz.EventFactory import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper import com.vitorpamplona.quartz.nip01Core.core.Tag -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.store.sqlite.sql.where +import com.vitorpamplona.quartz.utils.EventFactory class EventIndexesModule( val fts: FullTextSearchModule, @@ -116,7 +115,7 @@ class EventIndexesModule( stmt.bindString(2, event.pubKey) stmt.bindLong(3, event.createdAt) stmt.bindLong(4, event.kind.toLong()) - stmt.bindString(5, JsonMapper.mapper.writeValueAsString(event.tags)) + stmt.bindString(5, OptimizedJsonMapper.toJson(event.tags)) stmt.bindString(6, event.content) stmt.bindString(7, event.sig) if (event is AddressableEvent) { @@ -250,7 +249,7 @@ class EventIndexesModule( cursor.getString(1).intern(), cursor.getLong(2), cursor.getInt(3), - JsonMapper.mapper.readValue>>(cursor.getString(4)), + OptimizedJsonMapper.fromJsonToTagArray(cursor.getString(4)), cursor.getString(5).intern(), cursor.getString(6).intern(), ), @@ -279,7 +278,7 @@ class EventIndexesModule( cursor.getString(1).intern(), cursor.getLong(2), cursor.getInt(3), - JsonMapper.mapper.readValue>>(cursor.getString(4)), + OptimizedJsonMapper.fromJsonToTagArray(cursor.getString(4)), cursor.getString(5).intern(), cursor.getString(6).intern(), ), diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Utils.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Utils.kt deleted file mode 100644 index 0ffd6a0346..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Utils.kt +++ /dev/null @@ -1,166 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip03Timestamp.ots - -import java.security.NoSuchAlgorithmException -import java.security.SecureRandom - -/** - * Utility functions for (mostly) manipulating byte arrays. - */ -object Utils { - /** - * Fills a byte array with the given byte value. - * - * @param array the array to fill - * @param value the value to fill the array with - */ - @JvmStatic - fun arrayFill( - array: ByteArray, - value: Byte, - ) { - for (i in array.indices) { - array[i] = value - } - } - - /** - * Returns the first value that is not null. If all objects are null, then it returns null. - * - * @param items the array of Ts - * @param This describes my type parameter - * @return the first value that is not null. If all objects are null, then it returns null. - */ - @Deprecated("Not used by Java OpenTimestamps itself, and doesn't offer much useful functionality.") - fun coalesce(vararg items: T?): T? { - for (i in items) { - if (i != null) { - return i - } - } - - return null - } - - /** - * Returns a copy of the byte array argument, or null if the byte array argument is null. - * - * @param data the array of bytes to copy - * @return the copied byte array - */ - @JvmStatic - fun arraysCopy(data: ByteArray): ByteArray { - val copy = ByteArray(data.size) - System.arraycopy(data, 0, copy, 0, data.size) - - return copy - } - - /** - * Returns a byte array which is the result of concatenating the two passed in byte arrays. - * None of the passed in arrays may be null. - * - * @param array1 the first array of bytes - * @param array2 the second array of bytes - * @return a copy of array1 and array2 concatenated together - */ - @JvmStatic - fun arraysConcat( - array1: ByteArray, - array2: ByteArray, - ): ByteArray { - val array1and2 = ByteArray(array1.size + array2.size) - System.arraycopy(array1, 0, array1and2, 0, array1.size) - System.arraycopy(array2, 0, array1and2, array1.size, array2.size) - - return array1and2 - } - - /** - * Returns a given length array of random bytes. - * - * @param length the requested length of the byte array - * @return a given length array of random bytes - * @throws NoSuchAlgorithmException for Java 8 implementations - */ - @JvmStatic - @Throws(NoSuchAlgorithmException::class) - fun randBytes(length: Int): ByteArray { - // Java 6 & 7: - val random = SecureRandom() - val bytes = ByteArray(length) - random.nextBytes(bytes) - - // Java 8 (even more secure): - // SecureRandom.getInstanceStrong().nextBytes(bytes); - return bytes - } - - /** - * Returns a reversed copy of the passed in byte array. - * - * @param array the byte array to reverse - * @return a copy of the byte array, reversed - */ - @JvmStatic - fun arrayReverse(array: ByteArray): ByteArray { - val reversedArray = ByteArray(array.size) - - var i = array.size - 1 - var j = 0 - while (i >= 0) { - reversedArray[j] = array[i] - i-- - j++ - } - - return reversedArray - } - - /** - * Compares two byte arrays. - * - * @param left the left byte array to compare with - * @param right the right byte array to compare with - * @return 0 if the arrays are identical, negative if left < right, positive if left > right - */ - @JvmStatic - fun compare( - left: ByteArray, - right: ByteArray, - ): Int { - var i = 0 - var j = 0 - while (i < left.size && j < right.size) { - val a = (left[i].toInt() and 0xff) - val b = (right[j].toInt() and 0xff) - - if (a != b) { - return a - b - } - i++ - j++ - } - - return left.size - right.size - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/BlockstreamExplorer.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/BlockstreamExplorer.kt deleted file mode 100644 index f2f5b7d364..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/BlockstreamExplorer.kt +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip03Timestamp.ots.http - -import android.util.Log -import com.vitorpamplona.quartz.nip03Timestamp.ots.BitcoinExplorer -import com.vitorpamplona.quartz.nip03Timestamp.ots.BlockHeader -import java.net.URL -import java.util.concurrent.Executors - -class BlockstreamExplorer : BitcoinExplorer { - /** - * Retrieve the block information from the block hash. - * - * @param hash Hash of the block. - * @return the blockheader of the hash - * @throws Exception desc - */ - @Throws(Exception::class) - override fun block(hash: String): BlockHeader { - val url = URL("$EXPLORA_URL/block/$hash") - val task = Request(url) - val executor = Executors.newSingleThreadExecutor() - val future = executor.submit(task) - val take: Response = future.get() - executor.shutdown() - if (!take.isOk) throw Exception() - - val jsonObject = take.json - val merkleRoot = jsonObject!!.get("merkle_root").asText() - val time = jsonObject.get("timestamp").asInt().toString() - val blockHeader = BlockHeader(merkleRoot, hash, time) - Log.i("BlockstreamExplorer", take.fromUrl + " " + blockHeader) - return blockHeader - // log.warning("Cannot parse merkleroot from body: " + jsonObject + ": " + e.getMessage()); - } - - /** - * Retrieve the block hash from the block height. - * - * @param height Height of the block. - * @return the hash of the block at height height - * @throws Exception desc - */ - @Throws(Exception::class) - override fun blockHash(height: Int): String { - val url = URL("$EXPLORA_URL/block-height/$height") - val task = Request(url) - val executor = Executors.newSingleThreadExecutor() - val future = executor.submit(task) - val take = future.get() - executor.shutdown() - if (!take.isOk) throw Exception() - val blockHash = take.string - Log.i("BlockstreamExplorer", take.fromUrl + " " + blockHash) - return blockHash - } - - companion object { - private const val EXPLORA_URL = "https://blockstream.info/api" - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/Calendar.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/Calendar.kt deleted file mode 100644 index 7af8862993..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/Calendar.kt +++ /dev/null @@ -1,127 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip03Timestamp.ots.http - -import com.vitorpamplona.quartz.nip01Core.core.toHexKey -import com.vitorpamplona.quartz.nip03Timestamp.ots.ICalendar -import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamDeserializationContext -import com.vitorpamplona.quartz.nip03Timestamp.ots.Timestamp -import com.vitorpamplona.quartz.nip03Timestamp.ots.Timestamp.Companion.deserialize -import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.CommitmentNotFoundException -import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.DeserializationException -import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.ExceededSizeException -import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.UrlException -import java.net.URL - -/** - * Class representing remote calendar server interface. - */ -class Calendar( - val url: String, -) : ICalendar { - /** - * Submitting a digest to remote calendar. Returns a com.eternitywall.ots.Timestamp committing to that digest. - * - * @param digest The digest hash to send. - * @return the Timestamp received from the calendar. - * @throws ExceededSizeException if response is too big. - * @throws UrlException if url is not reachable. - * @throws DeserializationException if the data is corrupt - */ - @Throws(ExceededSizeException::class, UrlException::class, DeserializationException::class) - override fun submit(digest: ByteArray): Timestamp { - try { - val headers: MutableMap = HashMap() - headers.put("Accept", "application/vnd.opentimestamps.v1") - headers.put("User-Agent", "java-opentimestamps") - headers.put("Content-Type", "application/x-www-form-urlencoded") - - val obj = URL("$url/digest") - val task = Request(obj) - task.setData(digest) - task.setHeaders(headers) - val response = task.call() - val body = response.bytes - if (body.size > 10000) { - throw ExceededSizeException("Calendar response exceeded size limit") - } - - val ctx = StreamDeserializationContext(body) - return deserialize(ctx, digest) - } catch (e: ExceededSizeException) { - throw e - } catch (e: DeserializationException) { - throw e - } catch (e: Exception) { - throw UrlException(e.message) - } - } - - /** - * Get a timestamp for a given commitment. - * - * @param commitment The digest hash to send. - * @return the Timestamp from the calendar server (with blockchain information if already written). - * @throws ExceededSizeException if response is too big. - * @throws UrlException if url is not reachable. - * @throws CommitmentNotFoundException if commit is not found. - * @throws DeserializationException if the data is corrupt - */ - @Throws( - DeserializationException::class, - ExceededSizeException::class, - CommitmentNotFoundException::class, - UrlException::class, - ) - override fun getTimestamp(commitment: ByteArray): Timestamp { - try { - val headers: MutableMap = HashMap() - headers.put("Accept", "application/vnd.opentimestamps.v1") - headers.put("User-Agent", "java-opentimestamps") - headers.put("Content-Type", "application/x-www-form-urlencoded") - - val obj = URL(url + "/timestamp/" + commitment.toHexKey().lowercase()) - val task = Request(obj) - task.setHeaders(headers) - val response = task.call() - val body = response.bytes - if (body.size > 10000) { - throw ExceededSizeException("Calendar response exceeded size limit") - } - - if (!response.isOk) { - throw CommitmentNotFoundException("com.eternitywall.ots.Calendar response a status code != 200 which is: " + response.status) - } - - val ctx = StreamDeserializationContext(body) - - return deserialize(ctx, commitment) - } catch (e: DeserializationException) { - throw e - } catch (e: ExceededSizeException) { - throw e - } catch (e: CommitmentNotFoundException) { - throw e - } catch (e: Exception) { - throw UrlException(e.message) - } - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/CalendarAsyncSubmit.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/CalendarAsyncSubmit.kt deleted file mode 100644 index b03ac65231..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/CalendarAsyncSubmit.kt +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip03Timestamp.ots.http - -import com.vitorpamplona.quartz.nip03Timestamp.ots.ICalendarAsyncSubmit -import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamDeserializationContext -import com.vitorpamplona.quartz.nip03Timestamp.ots.Timestamp -import com.vitorpamplona.quartz.nip03Timestamp.ots.Timestamp.Companion.deserialize -import java.net.URL -import java.util.Optional -import java.util.concurrent.ArrayBlockingQueue -import java.util.concurrent.BlockingQueue - -/** - * For making async calls to a calendar server - */ -class CalendarAsyncSubmit( - private val url: String, - private val digest: ByteArray, -) : ICalendarAsyncSubmit { - private var queue: BlockingQueue> = ArrayBlockingQueue(1) - - fun setQueue(queue: BlockingQueue>) { - this.queue = queue - } - - @Throws(Exception::class) - override fun call(): Optional { - val headers: MutableMap = HashMap() - headers.put("Accept", "application/vnd.opentimestamps.v1") - headers.put("User-Agent", "java-opentimestamps") - headers.put("Content-Type", "application/x-www-form-urlencoded") - - val obj = URL("$url/digest") - val task = Request(obj) - task.setData(digest) - task.setHeaders(headers) - val response = task.call() - - if (response.isOk) { - val body = response.bytes - val ctx = StreamDeserializationContext(body) - val timestamp = deserialize(ctx, digest) - val of: Optional = Optional.of(timestamp) - queue.add(of) - return of - } - - queue.add(Optional.empty()) - - return Optional.empty() - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/Request.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/Request.kt deleted file mode 100644 index 025d4d7c15..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/Request.kt +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip03Timestamp.ots.http - -import android.util.Log -import java.io.DataOutputStream -import java.net.HttpURLConnection -import java.net.URL -import java.util.concurrent.Callable -import java.util.zip.GZIPInputStream - -/** - * For making an HTTP request. - */ -class Request( - private val url: URL, -) : Callable { - private var data: ByteArray? = null - private var headers: MutableMap = mutableMapOf() - - fun setData(data: ByteArray?) { - this.data = data - } - - fun setHeaders(headers: MutableMap) { - this.headers = headers - } - - @Throws(Exception::class) - override fun call(): Response { - val response = Response() - - try { - val httpURLConnection = url.openConnection() as HttpURLConnection - httpURLConnection.readTimeout = 10000 - httpURLConnection.connectTimeout = 10000 - httpURLConnection.setRequestProperty("User-Agent", "OpenTimestamps Java") - httpURLConnection.setRequestProperty("Accept", "application/json") - httpURLConnection.setRequestProperty("Accept-Encoding", "gzip") - - for (entry in headers.entries) { - httpURLConnection.setRequestProperty(entry.key, entry.value) - } - - if (data != null) { - httpURLConnection.setDoOutput(true) - httpURLConnection.requestMethod = "POST" - httpURLConnection.setRequestProperty( - "Content-Length", - "" + this.data!!.size.toString(), - ) - DataOutputStream(httpURLConnection.getOutputStream()).use { wr -> - wr.write(this.data, 0, this.data!!.size) - wr.flush() - } - } else { - httpURLConnection.requestMethod = "GET" - } - - httpURLConnection.connect() - - val responseCode = httpURLConnection.getResponseCode() - - Log.i("OpenTimestamp", "$responseCode responseCode ") - - response.status = responseCode - response.fromUrl = url.toString() - var `is` = httpURLConnection.getInputStream() - if ("gzip" == httpURLConnection.contentEncoding) { - `is` = GZIPInputStream(`is`) - } - response.setStream(`is`) - } catch (e: Exception) { - Log.w("OpenTimestamp", "$url exception $e") - } - - return response - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/Response.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/Response.kt deleted file mode 100644 index 403f8bbfcb..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/Response.kt +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip03Timestamp.ots.http - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.json.JsonMapper -import java.io.ByteArrayOutputStream -import java.io.Closeable -import java.io.IOException -import java.io.InputStream -import java.nio.charset.StandardCharsets - -/** - * Holds the response from an HTTP request. - */ -class Response : Closeable { - private var stream: InputStream? = null - - var fromUrl: String? = null - var status: Int? = null - - constructor() - - constructor(stream: InputStream) { - this.stream = stream - } - - fun setStream(stream: InputStream) { - this.stream = stream - } - - val isOk: Boolean - get() = this.status != null && 200 == this.status - - fun getStream(): InputStream = this.stream!! - - @get:Throws(IOException::class) - val string: String - get() = String(this.bytes, StandardCharsets.UTF_8) - - @get:Throws(IOException::class) - val bytes: ByteArray - get() { - val buffer = ByteArrayOutputStream() - var nRead: Int - val data = ByteArray(16384) - - while ((this.stream!!.read(data, 0, data.size).also { nRead = it }) != -1) { - buffer.write(data, 0, nRead) - } - - buffer.flush() - - return buffer.toByteArray() - } - - @get:Throws(IOException::class) - val json: JsonNode? - get() { - val jsonString = this.string - val builder = - JsonMapper.builder().build() - return builder.readTree(jsonString) - } - - override fun close() { - stream?.close() - stream = null - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpCalendar.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpCalendar.kt deleted file mode 100644 index 20e8d3bf8e..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpCalendar.kt +++ /dev/null @@ -1,138 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip03Timestamp.ots.okhttp - -import com.vitorpamplona.quartz.nip03Timestamp.ots.ICalendar -import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamDeserializationContext -import com.vitorpamplona.quartz.nip03Timestamp.ots.Timestamp -import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.CommitmentNotFoundException -import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.DeserializationException -import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.ExceededSizeException -import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.UrlException -import com.vitorpamplona.quartz.utils.Hex -import okhttp3.MediaType.Companion.toMediaType -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.RequestBody.Companion.toRequestBody - -/** - * Class representing remote calendar server interface. - */ -class OkHttpCalendar( - val url: String, - val client: OkHttpClient, -) : ICalendar { - /** - * Submitting a digest to remote calendar. Returns a com.eternitywall.ots.Timestamp committing to that digest. - * - * @param digest The digest hash to send. - * @return the Timestamp received from the calendar. - * @throws ExceededSizeException if response is too big. - * @throws UrlException if url is not reachable. - * @throws DeserializationException if the data is corrupt - */ - @Throws(ExceededSizeException::class, UrlException::class, DeserializationException::class) - override fun submit(digest: ByteArray): Timestamp { - try { - val url = "$url/digest" - - val mediaType = "application/x-www-form-urlencoded; charset=utf-8".toMediaType() - val requestBody = digest.toRequestBody(mediaType) - - val request = - Request - .Builder() - .header("Accept", "application/vnd.opentimestamps.v1") - .header("Content-Type", "application/x-www-form-urlencoded") - .url(url) - .post(requestBody) - .build() - - client.newCall(request).execute().use { - if (it.isSuccessful) { - val ctx = - StreamDeserializationContext( - it.body.bytes(), - ) - return Timestamp.deserialize(ctx, digest) - } else { - throw UrlException( - "Failed to open $url", - ) - } - } - } catch (e: ExceededSizeException) { - throw e - } catch (e: DeserializationException) { - throw e - } catch (e: Exception) { - throw UrlException(e.message) - } - } - - /** - * Get a timestamp for a given commitment. - * - * @param commitment The digest hash to send. - * @return the Timestamp from the calendar server (with blockchain information if already written). - * @throws ExceededSizeException if response is too big. - * @throws UrlException if url is not reachable. - * @throws CommitmentNotFoundException if commit is not found. - * @throws DeserializationException if the data is corrupt - */ - @Throws( - DeserializationException::class, - ExceededSizeException::class, - CommitmentNotFoundException::class, - UrlException::class, - ) - override fun getTimestamp(commitment: ByteArray): Timestamp { - try { - val url = url + "/timestamp/" + Hex.encode(commitment) - - val request = - Request - .Builder() - .header("Accept", "application/vnd.opentimestamps.v1") - .header("Content-Type", "application/x-www-form-urlencoded") - .url(url) - .get() - .build() - - client.newCall(request).execute().use { - if (it.isSuccessful) { - val ctx = StreamDeserializationContext(it.body.bytes()) - return Timestamp.deserialize(ctx, commitment) - } else { - throw CommitmentNotFoundException("Calendar response a status code != 200: " + it.code) - } - } - } catch (e: DeserializationException) { - throw e - } catch (e: ExceededSizeException) { - throw e - } catch (e: CommitmentNotFoundException) { - throw e - } catch (e: Exception) { - throw UrlException(e.message) - } - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpCalendarAsyncSubmit.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpCalendarAsyncSubmit.kt deleted file mode 100644 index 4a8ca91009..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpCalendarAsyncSubmit.kt +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip03Timestamp.ots.okhttp - -import com.vitorpamplona.quartz.nip03Timestamp.ots.ICalendarAsyncSubmit -import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamDeserializationContext -import com.vitorpamplona.quartz.nip03Timestamp.ots.Timestamp -import okhttp3.MediaType.Companion.toMediaType -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.RequestBody.Companion.toRequestBody -import java.util.Optional - -/** - * For making async calls to a calendar server - */ -class OkHttpCalendarAsyncSubmit( - private val url: String, - private val digest: ByteArray, - private val client: OkHttpClient, -) : ICalendarAsyncSubmit { - override fun call(): Optional { - val url = "$url/digest" - val mediaType = "application/x-www-form-urlencoded; charset=utf-8".toMediaType() - val requestBody = digest.toRequestBody(mediaType) - - val request = - Request - .Builder() - .header("Accept", "application/vnd.opentimestamps.v1") - .header("Content-Type", "application/x-www-form-urlencoded") - .url(url) - .post(requestBody) - .build() - - client.newCall(request).execute().use { - if (it.isSuccessful) { - val ctx = - StreamDeserializationContext( - it.body.bytes(), - ) - val timestamp = Timestamp.deserialize(ctx, digest) - return Optional.of(timestamp) - } else { - return Optional.empty() - } - } - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpCalendarBuilder.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpCalendarBuilder.kt deleted file mode 100644 index 691056b874..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpCalendarBuilder.kt +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip03Timestamp.ots.okhttp - -import com.vitorpamplona.quartz.nip03Timestamp.ots.CalendarBuilder -import com.vitorpamplona.quartz.nip03Timestamp.ots.ICalendar -import com.vitorpamplona.quartz.nip03Timestamp.ots.ICalendarAsyncSubmit -import okhttp3.OkHttpClient - -class OkHttpCalendarBuilder( - val clientFn: (url: String) -> OkHttpClient, -) : CalendarBuilder { - override fun newSyncCalendar(url: String): ICalendar = OkHttpCalendar(url, clientFn(url)) - - override fun newAsyncCalendar( - url: String, - digest: ByteArray, - ): ICalendarAsyncSubmit = OkHttpCalendarAsyncSubmit(url, digest, clientFn(url)) -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequest.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequest.kt deleted file mode 100644 index 8b5a4bbe6c..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequest.kt +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip46RemoteSigner - -import com.fasterxml.jackson.core.JsonGenerator -import com.fasterxml.jackson.core.JsonParser -import com.fasterxml.jackson.databind.DeserializationContext -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.SerializerProvider -import com.fasterxml.jackson.databind.deser.std.StdDeserializer -import com.fasterxml.jackson.databind.ser.std.StdSerializer -import com.vitorpamplona.quartz.nip01Core.jackson.toTypedArray -import com.vitorpamplona.quartz.utils.bytesUsedInMemory -import com.vitorpamplona.quartz.utils.pointerSizeInBytes - -open class BunkerRequest( - val id: String, - val method: String, - val params: Array = emptyArray(), -) : BunkerMessage() { - override fun countMemory(): Int = - 3 * pointerSizeInBytes + // 3 fields, 4 bytes each reference (32bit) - id.bytesUsedInMemory() + - method.bytesUsedInMemory() + - params.sumOf { pointerSizeInBytes + it.bytesUsedInMemory() } - - class BunkerRequestDeserializer : StdDeserializer(BunkerRequest::class.java) { - override fun deserialize( - jp: JsonParser, - ctxt: DeserializationContext, - ): BunkerRequest { - val jsonObject: JsonNode = jp.codec.readTree(jp) - val id = jsonObject.get("id").asText().intern() - val method = jsonObject.get("method").asText().intern() - val params = jsonObject.get("params")?.toTypedArray { it.asText().intern() } ?: emptyArray() - - return when (method) { - BunkerRequestConnect.METHOD_NAME -> BunkerRequestConnect.parse(id, params) - BunkerRequestGetPublicKey.METHOD_NAME -> BunkerRequestGetPublicKey.parse(id, params) - BunkerRequestGetRelays.METHOD_NAME -> BunkerRequestGetRelays.parse(id, params) - - BunkerRequestNip04Decrypt.METHOD_NAME -> BunkerRequestNip04Decrypt.parse(id, params) - BunkerRequestNip04Encrypt.METHOD_NAME -> BunkerRequestNip04Encrypt.parse(id, params) - BunkerRequestNip44Decrypt.METHOD_NAME -> BunkerRequestNip44Decrypt.parse(id, params) - BunkerRequestNip44Encrypt.METHOD_NAME -> BunkerRequestNip44Encrypt.parse(id, params) - - BunkerRequestPing.METHOD_NAME -> BunkerRequestPing.parse(id, params) - BunkerRequestSign.METHOD_NAME -> BunkerRequestSign.parse(id, params) - else -> BunkerRequest(id, method, params) - } - } - } - - class BunkerRequestSerializer : StdSerializer(BunkerRequest::class.java) { - override fun serialize( - value: BunkerRequest, - gen: JsonGenerator, - provider: SerializerProvider, - ) { - gen.writeStartObject() - gen.writeStringField("id", value.id) - gen.writeStringField("method", value.method) - gen.writeArrayFieldStart("params") - value.params.forEach { - gen.writeString(it) - } - gen.writeEndArray() - gen.writeEndObject() - } - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponse.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponse.kt deleted file mode 100644 index d6272a6aa6..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponse.kt +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip46RemoteSigner - -import com.fasterxml.jackson.core.JsonGenerator -import com.fasterxml.jackson.core.JsonParser -import com.fasterxml.jackson.databind.DeserializationContext -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.SerializerProvider -import com.fasterxml.jackson.databind.deser.std.StdDeserializer -import com.fasterxml.jackson.databind.ser.std.StdSerializer -import com.vitorpamplona.quartz.utils.Hex -import com.vitorpamplona.quartz.utils.bytesUsedInMemory -import com.vitorpamplona.quartz.utils.pointerSizeInBytes - -open class BunkerResponse( - val id: String, - val result: String?, - val error: String?, -) : BunkerMessage() { - override fun countMemory(): Int = - 3 * pointerSizeInBytes + // 3 fields, 4 bytes each reference (32bit) - id.bytesUsedInMemory() + - (result?.bytesUsedInMemory() ?: 0) + - (error?.bytesUsedInMemory() ?: 0) - - class BunkerResponseDeserializer : StdDeserializer(BunkerResponse::class.java) { - override fun deserialize( - jp: JsonParser, - ctxt: DeserializationContext, - ): BunkerResponse { - val jsonObject: JsonNode = jp.codec.readTree(jp) - - val id = jsonObject.get("id").asText().intern() - val result = jsonObject.get("result")?.asText() - val error = jsonObject.get("error")?.asText() - - if (error != null) { - return com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseError - .parse(id, result, error) - } - - if (result != null) { - when (result) { - BunkerResponseAck.RESULT -> return BunkerResponseAck.parse(id, result, error) - BunkerResponsePong.RESULT -> return BunkerResponsePong.parse(id, result, error) - else -> { - if (result.length == 64 && Hex.isHex(result)) { - return BunkerResponsePublicKey.parse(id, result) - } - - if (result.get(0) == '{') { - try { - return com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseEvent - .parse(id, result) - } catch (_: Exception) { - } - - try { - return BunkerResponseGetRelays.parse(id, result) - } catch (_: Exception) { - } - } - - return BunkerResponse(id, result, error) - } - } - } - - return BunkerResponse(id, result, error) - } - } - - class BunkerResponseSerializer : StdSerializer(BunkerResponse::class.java) { - override fun serialize( - value: BunkerResponse, - gen: JsonGenerator, - provider: SerializerProvider, - ) { - gen.writeStartObject() - gen.writeStringField("id", value.id) - value.result?.let { gen.writeStringField("result", value.result) } - value.error?.let { gen.writeStringField("error", it) } - gen.writeEndObject() - } - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/SecretKeyOrEmptySpec.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/SecretKeyOrEmptySpec.kt deleted file mode 100644 index a5cc12e251..0000000000 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/SecretKeyOrEmptySpec.kt +++ /dev/null @@ -1,180 +0,0 @@ -/** - * Copyright (c) 2025 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.quartz.nip49PrivKeyEnc - -import java.security.MessageDigest -import java.security.spec.KeySpec -import javax.crypto.SecretKey - -/** - * This class specifies a secret key in a provider-independent fashion. - * - * - * It can be used to construct a `SecretKey` from a byte array, - * without having to go through a (provider-based) - * `SecretKeyFactory`. - * - * - * This class is only useful for raw secret keys that can be represented as - * a byte array and have no key parameters associated with them, e.g., DES or - * Triple DES keys. - * - * @author Jan Luehe - * - * @see SecretKey - * - * @see javax.crypto.SecretKeyFactory - * - * @since 1.4 - */ -class SecretKeyOrEmptySpec : - KeySpec, - SecretKey { - /** - * The secret key. - * - * @serial - */ - private val key: ByteArray - - /** - * The name of the algorithm associated with this key. - * - * @serial - */ - private val algorithm: String - - /** - * Constructs a secret key from the given byte array. - * - * - * This constructor does not check if the given bytes indeed specify a - * secret key of the specified algorithm. For example, if the algorithm is - * DES, this constructor does not check if `key` is 8 bytes - * long, and also does not check for weak or semi-weak keys. - * In order for those checks to be performed, an algorithm-specific - * *key specification* class - * - * @param key the key material of the secret key. The contents of - * the array are copied to protect against subsequent modification. - * @param algorithm the name of the secret-key algorithm to be associated - * with the given key material. - * See Appendix A in the [ - * Java Cryptography Architecture Reference Guide]({@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA) - * for information about standard algorithm names. - * @exception IllegalArgumentException if `algorithm` - * is null or `key` is null or empty. - */ - constructor(key: ByteArray, algorithm: String) { - this.key = key.clone() - this.algorithm = algorithm - } - - /** - * Returns the name of the algorithm associated with this secret key. - * - * @return the secret key algorithm. - */ - override fun getAlgorithm(): String = this.algorithm - - /** - * Returns the name of the encoding format for this secret key. - * - * @return the string "RAW". - */ - override fun getFormat(): String = "RAW" - - /** - * Returns the key material of this secret key. - * - * @return the key material. Returns a new array - * each time this method is called. - */ - override fun getEncoded(): ByteArray = this.key.clone() - - /** - * Calculates a hash code value for the object. - * Objects that are equal will also have the same hashcode. - */ - override fun hashCode(): Int { - var retval = 0 - for (i in 1.. fromJsonTo(json: String): T = defaultMapper.readValue(json, T::class.java) + + inline fun fromJsonTo(json: InputStream): T = defaultMapper.readValue(json, T::class.java) + + fun toJson(event: ArrayNode): String = defaultMapper.writeValueAsString(event) + + fun toJson(event: ObjectNode?): String = defaultMapper.writeValueAsString(event) + + fun toJson(value: Any): String = defaultMapper.writeValueAsString(value) +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/background/queries/DecryptZapQuery.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/background/queries/DecryptZapQuery.kt index 9e496471ea..4cc962d03d 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/background/queries/DecryptZapQuery.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/background/queries/DecryptZapQuery.kt @@ -24,7 +24,7 @@ import android.content.ContentResolver import androidx.core.net.toUri import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.verify +import com.vitorpamplona.quartz.nip01Core.crypto.verify import com.vitorpamplona.quartz.nip55AndroidSigner.api.CommandType import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.ZapEventDecryptionResult diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/background/queries/SignQuery.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/background/queries/SignQuery.kt index bf1bc9924b..836bf208ff 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/background/queries/SignQuery.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/background/queries/SignQuery.kt @@ -22,15 +22,15 @@ package com.vitorpamplona.quartz.nip55AndroidSigner.api.background.queries import android.content.ContentResolver import androidx.core.net.toUri -import com.vitorpamplona.quartz.EventFactory import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.verify +import com.vitorpamplona.quartz.nip01Core.crypto.verify import com.vitorpamplona.quartz.nip55AndroidSigner.api.CommandType import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.background.utils.getStringByName import com.vitorpamplona.quartz.nip55AndroidSigner.api.background.utils.query +import com.vitorpamplona.quartz.utils.EventFactory class SignQuery( val loggedInUser: HexKey, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/background/utils/ContentResolverExt.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/background/utils/ContentResolverExt.kt index ae940905b4..ccb95a789c 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/background/utils/ContentResolverExt.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/background/utils/ContentResolverExt.kt @@ -23,9 +23,9 @@ package com.vitorpamplona.quartz.nip55AndroidSigner.api.background.utils import android.content.ContentResolver import android.database.Cursor import android.net.Uri -import android.util.Log import com.vitorpamplona.quartz.nip55AndroidSigner.api.IResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult +import com.vitorpamplona.quartz.utils.Log fun ContentResolver.query( uri: Uri, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/IntentRequestManager.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/IntentRequestManager.kt index c3ff9e325b..ff5a3de985 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/IntentRequestManager.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/IntentRequestManager.kt @@ -22,11 +22,11 @@ package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground import android.content.ActivityNotFoundException import android.content.Intent -import android.util.Log import androidx.collection.LruCache import com.vitorpamplona.quartz.nip55AndroidSigner.api.IResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.RandomInstance import com.vitorpamplona.quartz.utils.tryAndWait import kotlin.coroutines.Continuation diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/requests/LoginRequest.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/requests/LoginRequest.kt index 39a02fa9c1..9da2f0f3c5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/requests/LoginRequest.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/requests/LoginRequest.kt @@ -22,8 +22,8 @@ package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.reque import android.content.Intent import androidx.core.net.toUri -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper import com.vitorpamplona.quartz.nip42RelayAuth.RelayAuthEvent +import com.vitorpamplona.quartz.nip55AndroidSigner.JsonMapperNip55 import com.vitorpamplona.quartz.nip55AndroidSigner.api.CommandType import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.Permission @@ -42,7 +42,7 @@ class LoginRequest { fun assemble(permissions: List = DefaultPermissions): Intent { val intent = Intent(Intent.ACTION_VIEW, "nostrsigner:".toUri()) intent.putExtra("type", CommandType.GET_PUBLIC_KEY.code) - intent.putExtra("permissions", JsonMapper.mapper.writeValueAsString(permissions)) + intent.putExtra("permissions", JsonMapperNip55.toJson(permissions)) return intent } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/SignResponse.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/SignResponse.kt index d37fb0d9af..74a8c8375a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/SignResponse.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/SignResponse.kt @@ -20,12 +20,12 @@ */ package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses -import com.vitorpamplona.quartz.EventFactory import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.verify +import com.vitorpamplona.quartz.nip01Core.crypto.verify import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult +import com.vitorpamplona.quartz.utils.EventFactory class SignResponse { companion object { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/results/IntentResult.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/results/IntentResult.kt index 58844729be..86c612afa3 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/results/IntentResult.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/results/IntentResult.kt @@ -21,17 +21,19 @@ package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results import android.content.Intent -import com.fasterxml.jackson.module.kotlin.readValue -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.core.OptimizedSerializable +import com.vitorpamplona.quartz.nip55AndroidSigner.JsonMapperNip55 +import kotlinx.serialization.Serializable +@Serializable data class IntentResult( val `package`: String? = null, val result: String? = null, val event: String? = null, val id: String? = null, val rejected: Boolean = false, -) { - fun toJson(): String = JsonMapper.mapper.writeValueAsString(this) +) : OptimizedSerializable { + fun toJson(): String = JsonMapperNip55.toJson(this) fun toIntent(): Intent { val intent = Intent() @@ -52,8 +54,8 @@ data class IntentResult( rejected = data.extras?.containsKey("rejected") == true, ) - fun fromJson(json: String): IntentResult = JsonMapper.mapper.readValue(json) + fun fromJson(json: String): IntentResult = JsonMapperNip55.fromJsonTo(json) - fun fromJsonArray(json: String): List = JsonMapper.mapper.readValue>(json) + fun fromJsonArray(json: String): List = JsonMapperNip55.fromJsonTo>(json) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/permission/Permission.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/permission/Permission.kt index 9c1511b532..06a1c032e2 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/permission/Permission.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/api/permission/Permission.kt @@ -20,18 +20,18 @@ */ package com.vitorpamplona.quartz.nip55AndroidSigner.api.permission -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip55AndroidSigner.JsonMapperNip55 import com.vitorpamplona.quartz.nip55AndroidSigner.api.CommandType class Permission( val type: CommandType?, val kind: Int? = null, ) { - fun toJson(): String = JsonMapper.mapper.writeValueAsString(this) + fun toJson(): String = JsonMapperNip55.toJson(this) companion object { - fun fromJson(json: String): Permission = JsonMapper.mapper.readValue(json, Permission::class.java) + fun fromJson(json: String): Permission = JsonMapperNip55.fromJsonTo(json) - fun fromJsonArray(json: String): Array = JsonMapper.mapper.readValue(json, Array::class.java) + fun fromJsonArray(json: String): Array = JsonMapperNip55.fromJsonTo>(json) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/client/NostrSignerExternal.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/client/NostrSignerExternal.kt index ffb6ec90af..c08d638079 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/client/NostrSignerExternal.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip55AndroidSigner/client/NostrSignerExternal.kt @@ -173,6 +173,9 @@ class NostrSignerExternal( throw convertExceptions("Could not decrypt private zap", result) } + // always ready + override fun hasForegroundSupport() = hasForegroundActivity() + fun convertExceptions( title: String, result: SignerResult.RequestAddressed<*>, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.android.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.kt rename to quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.android.kt index 6c327f4238..ffb4c0eadf 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.android.kt @@ -23,11 +23,11 @@ package com.vitorpamplona.quartz.utils import com.goterl.lazysodium.LazySodiumAndroid import com.goterl.lazysodium.SodiumAndroid -object LibSodiumInstance { +actual object LibSodiumInstance { private val libSodium = SodiumAndroid() private val lazySodium = LazySodiumAndroid(libSodium) - fun cryptoAeadXChaCha20Poly1305IetfDecrypt( + actual fun cryptoAeadXChaCha20Poly1305IetfDecrypt( message: ByteArray, nSec: ByteArray, ciphertext: ByteArray, @@ -47,7 +47,7 @@ object LibSodiumInstance { k, ) - fun cryptoAeadXChaCha20Poly1305IetfEncrypt( + actual fun cryptoAeadXChaCha20Poly1305IetfEncrypt( ciphertext: ByteArray, message: ByteArray, ad: ByteArray, @@ -67,7 +67,7 @@ object LibSodiumInstance { k, ) - fun cryptoStreamChaCha20IetfXor( + actual fun cryptoStreamChaCha20IetfXor( message: ByteArray, nonce: ByteArray?, key: ByteArray?, @@ -78,7 +78,7 @@ object LibSodiumInstance { } // This function wasn't available in the bindings library. I had to move them here from C - fun cryptoStreamXChaCha20Xor( + actual fun cryptoStreamXChaCha20Xor( messageBytes: ByteArray, nonce: ByteArray, key: ByteArray, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Log.android.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Log.android.kt new file mode 100644 index 0000000000..150d89ea52 --- /dev/null +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Log.android.kt @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +actual object Log { + actual fun w( + tag: String, + message: String, + throwable: Throwable?, + ) { + if (throwable != null) { + android.util.Log.w(tag, message, throwable) + } else { + android.util.Log.w(tag, message) + } + } + + actual fun e( + tag: String, + message: String, + throwable: Throwable?, + ) { + if (throwable != null) { + android.util.Log.e(tag, message, throwable) + } else { + android.util.Log.e(tag, message) + } + } + + actual fun d( + tag: String, + message: String, + ) { + android.util.Log.d(tag, message) + } + + actual fun i( + tag: String, + message: String, + ) { + android.util.Log.i(tag, message) + } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/Platform.android.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Platform.android.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/Platform.android.kt rename to quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Platform.android.kt index 5a6ac25b4c..727bba5804 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/Platform.android.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Platform.android.kt @@ -18,6 +18,8 @@ * 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.quartz +package com.vitorpamplona.quartz.utils actual fun platform() = "Android" + +actual fun currentTimeSeconds() = System.currentTimeMillis() / 1000 diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.android.kt similarity index 82% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.kt rename to quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.android.kt index 770a8f13c5..c66cb78e06 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.kt +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.android.kt @@ -22,37 +22,37 @@ package com.vitorpamplona.quartz.utils import fr.acinq.secp256k1.Secp256k1 -object Secp256k1Instance { +actual object Secp256k1Instance { private val h02 = Hex.decode("02") private val secp256k1 = Secp256k1.get() - fun compressedPubKeyFor(privKey: ByteArray) = secp256k1.pubKeyCompress(secp256k1.pubkeyCreate(privKey)) + actual fun compressedPubKeyFor(privKey: ByteArray) = secp256k1.pubKeyCompress(secp256k1.pubkeyCreate(privKey)) - fun isPrivateKeyValid(il: ByteArray): Boolean = secp256k1.secKeyVerify(il) + actual fun isPrivateKeyValid(il: ByteArray): Boolean = secp256k1.secKeyVerify(il) - fun signSchnorr( + actual fun signSchnorr( data: ByteArray, privKey: ByteArray, - nonce: ByteArray? = RandomInstance.bytes(32), + nonce: ByteArray?, ): ByteArray = secp256k1.signSchnorr(data, privKey, nonce) - fun signSchnorr( + actual fun signSchnorr( data: ByteArray, privKey: ByteArray, ): ByteArray = secp256k1.signSchnorr(data, privKey, null) - fun verifySchnorr( + actual fun verifySchnorr( signature: ByteArray, hash: ByteArray, pubKey: ByteArray, ): Boolean = secp256k1.verifySchnorr(signature, hash, pubKey) - fun privateKeyAdd( + actual fun privateKeyAdd( first: ByteArray, second: ByteArray, ): ByteArray = secp256k1.privKeyTweakAdd(first, second) - fun pubKeyTweakMulCompact( + actual fun pubKeyTweakMulCompact( pubKey: ByteArray, privateKey: ByteArray, ): ByteArray = secp256k1.pubKeyTweakMul(h02 + pubKey, privateKey).copyOfRange(1, 33) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.android.kt b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.android.kt new file mode 100644 index 0000000000..8863598825 --- /dev/null +++ b/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.android.kt @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import androidx.core.net.toUri +import java.net.URLDecoder + +actual class UriParser actual constructor( + uri: String, +) { + val myUri = uri.toUri() + + val fragments: Map by lazy { + myUri.fragment?.ifBlank { null }?.let { keyValuePair -> + keyValuePair.split('&').associate { paramValue -> + val parts = paramValue.split("=", limit = 2) + if (parts.size == 2) { + parts[0] to URLDecoder.decode(parts[1], "UTF-8") + } else { + parts[0] to "" // Handle parameters without a value, e.g., "param&other=value" + } + } + } ?: emptyMap() + } + + actual fun scheme(): String? = myUri.scheme + + actual fun host(): String? = myUri.host + + actual fun port(): Int? { + // android.net.Uri.getPort() returns -1 if the port is not set, so we handle that case. + val port = myUri.port + return if (port == -1) null else port + } + + actual fun path(): String? = myUri.path + + actual fun queryParameterNames() = myUri.queryParameterNames + + actual fun getQueryParameter(param: String) = myUri.getQueryParameter(param) + + actual fun fragments(): Map = fragments +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OtsBlockHeightCache.kt b/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/TestResourceLoader.kt similarity index 79% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OtsBlockHeightCache.kt rename to quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/TestResourceLoader.kt index 602f617110..9a271521d6 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OtsBlockHeightCache.kt +++ b/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/TestResourceLoader.kt @@ -18,12 +18,13 @@ * 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.quartz.nip03Timestamp.ots.okhttp +package com.vitorpamplona.quartz -import android.util.LruCache -import com.vitorpamplona.quartz.nip03Timestamp.ots.BlockHeader - -class OtsBlockHeightCache { - val cacheHeaders = LruCache(100) - val cacheHeights = LruCache(100) +actual class TestResourceLoader { + actual fun loadString(file: String): String = + this@TestResourceLoader + .javaClass.classLoader!! + .getResourceAsStream(file) + .bufferedReader() + .use { it.readText() } } diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexerMemoryTest.kt b/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexerMemoryTest.kt new file mode 100644 index 0000000000..9fd22ad09d --- /dev/null +++ b/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexerMemoryTest.kt @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.hints + +import com.vitorpamplona.quartz.utils.usedMemoryMb +import kotlin.test.Test + +class HintIndexerMemoryTest { + @Test + fun testSizeInMemory() { + System.gc() + Thread.sleep(1000) + + val startingMemory = Runtime.getRuntime().usedMemoryMb() + val result = HintIndexer() + val endingMemory = Runtime.getRuntime().usedMemoryMb() + + println("Filter using ${endingMemory - startingMemory}MB") + } +} diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/EventDbQueryAssemblerTest.kt b/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqllite/EventDbQueryAssemblerTest.kt similarity index 99% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/EventDbQueryAssemblerTest.kt rename to quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqllite/EventDbQueryAssemblerTest.kt index 78e75b1016..6eacd02329 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqlite/EventDbQueryAssemblerTest.kt +++ b/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/sqllite/EventDbQueryAssemblerTest.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.quartz.nip01Core.store.sqlite import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import junit.framework.TestCase -import org.junit.Test +import kotlin.test.Test class EventDbQueryAssemblerTest { val builder = EventIndexesModule(FullTextSearchModule()) diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/utils/RuntimeExt.kt b/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/utils/RuntimeExt.kt index b4d47698ab..816133dd49 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/utils/RuntimeExt.kt +++ b/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/utils/RuntimeExt.kt @@ -20,8 +20,10 @@ */ package com.vitorpamplona.quartz.utils +import kotlin.math.round + fun Runtime.usedMemoryMb(): Long { - val totalMemoryMb = totalMemory() / (1024 * 1024) - val freeMemoryMb = freeMemory() / (1024 * 1024) + val totalMemoryMb = round(totalMemory() / (1024 * 1024.0)).toLong() + val freeMemoryMb = round(freeMemory() / (1024 * 1024.0)).toLong() return totalMemoryMb - freeMemoryMb } diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/relayDB.txt b/quartz/src/androidUnitTest/resources/relayDB.txt similarity index 100% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/relayDB.txt rename to quartz/src/androidUnitTest/resources/relayDB.txt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/AudioHeaderEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/AudioHeaderEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/AudioHeaderEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/AudioHeaderEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/DownloadUrlTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/DownloadUrlTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/DownloadUrlTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/DownloadUrlTag.kt index 501ce46f6d..464adcb174 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/DownloadUrlTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/DownloadUrlTag.kt @@ -27,7 +27,6 @@ class DownloadUrlTag { companion object { const val TAG_NAME = "download_url" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class DownloadUrlTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/StreamUrlTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/StreamUrlTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/StreamUrlTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/StreamUrlTag.kt index 7cb18ba198..ef720f1654 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/StreamUrlTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/StreamUrlTag.kt @@ -27,7 +27,6 @@ class StreamUrlTag { companion object { const val TAG_NAME = "stream_url" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class StreamUrlTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/WaveformTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/WaveformTag.kt similarity index 86% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/WaveformTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/WaveformTag.kt index fc383cdc75..97ef46af1b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/WaveformTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/header/tags/WaveformTag.kt @@ -20,9 +20,8 @@ */ package com.vitorpamplona.quartz.experimental.audio.header.tags -import com.fasterxml.jackson.module.kotlin.readValue +import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import com.vitorpamplona.quartz.nip01Core.core.has -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper import com.vitorpamplona.quartz.utils.ensure class WaveformTag( @@ -33,17 +32,15 @@ class WaveformTag( companion object { const val TAG_NAME = "waveform" - @JvmStatic fun parse(tag: Array): WaveformTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } ensure(tag[1].isNotEmpty()) { return null } - val wave = runCatching { JsonMapper.mapper.readValue>(tag[1]) }.getOrNull() + val wave = runCatching { JsonMapper.fromJson>(tag[1]) }.getOrNull() if (wave.isNullOrEmpty()) return null return WaveformTag(wave) } - @JvmStatic - fun assemble(wave: List) = arrayOf(TAG_NAME, JsonMapper.mapper.writeValueAsString(wave)) + fun assemble(wave: List) = arrayOf(TAG_NAME, JsonMapper.toJson(wave)) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/AudioTrackEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/AudioTrackEvent.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/AudioTrackEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/AudioTrackEvent.kt index 3c9096d1cf..e87d86d880 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/AudioTrackEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/AudioTrackEvent.kt @@ -30,10 +30,11 @@ import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.utils.TimeUtils -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable class AudioTrackEvent( @@ -58,13 +59,14 @@ class AudioTrackEvent( const val KIND = 31337 const val ALT_DESCRIPTION = "Audio track" + @OptIn(ExperimentalUuidApi::class) fun build( type: String, media: String, price: String? = null, cover: String? = null, subject: String? = null, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = eventTemplate(KIND, "", createdAt) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/CoverTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/CoverTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/CoverTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/CoverTag.kt index 8f260c5525..a6577b3fc5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/CoverTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/CoverTag.kt @@ -27,7 +27,6 @@ class CoverTag { companion object { const val TAG_NAME = "cover" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class CoverTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/MediaTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/MediaTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/MediaTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/MediaTag.kt index 49bb66f49f..fc826b3a4f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/MediaTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/MediaTag.kt @@ -27,7 +27,6 @@ class MediaTag { companion object { const val TAG_NAME = "media" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class MediaTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/ParticipantTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/ParticipantTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/ParticipantTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/ParticipantTag.kt index 3f7e65b260..8f9ac686ca 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/ParticipantTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/ParticipantTag.kt @@ -40,7 +40,6 @@ data class ParticipantTag( companion object { const val TAG_NAME = "p" - @JvmStatic fun parse(tag: Tag): ParticipantTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -48,7 +47,6 @@ data class ParticipantTag( return ParticipantTag(tag[1], tag.getOrNull(2)?.let { RelayUrlNormalizer.normalizeOrNull(it) }) } - @JvmStatic fun parseKey(tag: Tag): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -56,7 +54,6 @@ data class ParticipantTag( return tag[1] } - @JvmStatic fun assemble( pubkey: HexKey, relayHint: NormalizedRelayUrl? = null, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/PriceTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/PriceTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/PriceTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/PriceTag.kt index a331cd0652..9f6a374ee0 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/PriceTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/PriceTag.kt @@ -27,7 +27,6 @@ class PriceTag { companion object { const val TAG_NAME = "price" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class PriceTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/TypeTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/TypeTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/TypeTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/TypeTag.kt index de62b0e615..4969a260ea 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/TypeTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/audio/track/tags/TypeTag.kt @@ -27,7 +27,6 @@ class TypeTag { companion object { const val TAG_NAME = "c" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class TypeTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/BountyAddValueEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/BountyAddValueEvent.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/BountyAddValueEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/BountyAddValueEvent.kt index d0ac4f63e6..b1a07a300f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/BountyAddValueEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/BountyAddValueEvent.kt @@ -29,9 +29,10 @@ import com.vitorpamplona.quartz.nip01Core.tags.people.pTag import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag import com.vitorpamplona.quartz.nip10Notes.tags.markedETag +import com.vitorpamplona.quartz.nip10Notes.tags.toMarkedETag import com.vitorpamplona.quartz.nip31Alts.alt +import com.vitorpamplona.quartz.utils.BigDecimal import com.vitorpamplona.quartz.utils.TimeUtils -import java.math.BigDecimal /** * This is a huge hack from back in the days... diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/EventExt.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/EventExt.kt index 40b508a554..4e926999e7 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/EventExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/EventExt.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.quartz.experimental.bounties import com.vitorpamplona.quartz.nip01Core.core.Event -import java.math.BigDecimal +import com.vitorpamplona.quartz.utils.BigDecimal fun Event.bountyBaseReward(): BigDecimal? = tags.bountyBaseReward() diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/RewardTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/RewardTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/RewardTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/RewardTag.kt index 61842ebf45..8bd098df12 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/RewardTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/RewardTag.kt @@ -21,14 +21,13 @@ package com.vitorpamplona.quartz.experimental.bounties import com.vitorpamplona.quartz.nip01Core.core.has +import com.vitorpamplona.quartz.utils.BigDecimal import com.vitorpamplona.quartz.utils.ensure -import java.math.BigDecimal class RewardTag { companion object { const val TAG_NAME = "reward" - @JvmStatic fun parse(tag: Array): BigDecimal? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -37,7 +36,6 @@ class RewardTag { return runCatching { BigDecimal(tag[1]) }.getOrNull() } - @JvmStatic fun assemble(amount: BigDecimal) = arrayOf(TAG_NAME, amount.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/bounties/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/DecoupledCipher.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/DecoupledCipher.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/DecoupledCipher.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/DecoupledCipher.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/EncryptionKeyCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/EncryptionKeyCache.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/EncryptionKeyCache.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/EncryptionKeyCache.kt index 0a812043ff..39fd0a1629 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/EncryptionKeyCache.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/EncryptionKeyCache.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.quartz.experimental.decoupling -import android.util.LruCache +import androidx.collection.LruCache import com.vitorpamplona.quartz.nip01Core.core.HexKey object EncryptionKeyCache { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/EncryptionKeyDerivation.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/EncryptionKeyDerivation.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/EncryptionKeyDerivation.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/EncryptionKeyDerivation.kt index 7b50b63bd4..8b4c227888 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/EncryptionKeyDerivation.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/EncryptionKeyDerivation.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.utils.sha256.sha256 class EncryptionKeyDerivation { companion object { - private val saltPrefix = "nip44kd".toByteArray(Charsets.UTF_8) + private val saltPrefix = "nip44kd".encodeToByteArray() fun derivePrivateKey( privKey: ByteArray, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/EncryptionKeyListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/EncryptionKeyListEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/EncryptionKeyListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/EncryptionKeyListEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/tags/KeyTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/tags/KeyTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/tags/KeyTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/tags/KeyTag.kt index 3f5a8f11f3..ab6b593229 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/tags/KeyTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/decoupling/setup/tags/KeyTag.kt @@ -44,7 +44,6 @@ class KeyTag( return true } - @JvmStatic fun parse(tag: Array): KeyTag? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -53,7 +52,6 @@ class KeyTag( return KeyTag(tag[1], tag[2]) } - @JvmStatic fun assemble( key: HexKey, nonce: HexKey, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/edits/TextNoteModificationEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/edits/TextNoteModificationEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/edits/TextNoteModificationEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/edits/TextNoteModificationEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/EphemeralChatEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/EphemeralChatEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/EphemeralChatEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/EphemeralChatEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/RoomId.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/RoomId.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/RoomId.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/RoomId.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/tags/RelayTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/tags/RelayTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/tags/RelayTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/tags/RelayTag.kt index 3399d98fc9..2c1ca09e29 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/tags/RelayTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/tags/RelayTag.kt @@ -30,10 +30,8 @@ class RelayTag { companion object { const val TAG_NAME = "relay" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun parse(tag: Array): NormalizedRelayUrl? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -42,7 +40,6 @@ class RelayTag { return RelayUrlNormalizer.normalizeOrNull(tag[1]) } - @JvmStatic fun assemble(relay: NormalizedRelayUrl) = arrayOf(TAG_NAME, relay.url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/tags/RoomTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/tags/RoomTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/tags/RoomTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/tags/RoomTag.kt index e97ea19d96..203f42bd72 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/tags/RoomTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/chat/tags/RoomTag.kt @@ -28,10 +28,8 @@ class RoomTag { companion object { const val TAG_NAME = "d" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -39,7 +37,6 @@ class RoomTag { return tag[1] } - @JvmStatic fun assemble(room: String) = arrayOf(TAG_NAME, room) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/db/EphemeralRoom.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/db/EphemeralRoom.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/db/EphemeralRoom.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/db/EphemeralRoom.kt index 5d687851d9..a92e39f3fc 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/db/EphemeralRoom.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/db/EphemeralRoom.kt @@ -25,7 +25,7 @@ import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.utils.cache.LargeCache import kotlinx.coroutines.flow.MutableStateFlow @Stable diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/db/EphemeralRoomCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/db/EphemeralRoomCache.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/db/EphemeralRoomCache.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/db/EphemeralRoomCache.kt index 2785203e06..ee1440a5cc 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/db/EphemeralRoomCache.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/db/EphemeralRoomCache.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.quartz.experimental.ephemChat.db import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.utils.cache.LargeCache class EphemeralRoomCache { val rooms = LargeCache() diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/EphemeralChatListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/EphemeralChatListEvent.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/EphemeralChatListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/EphemeralChatListEvent.kt index 84a70f1dad..707be49be1 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/EphemeralChatListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/EphemeralChatListEvent.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.quartz.experimental.ephemChat.list import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId import com.vitorpamplona.quartz.experimental.ephemChat.list.tags.RoomIdTag +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder @@ -30,7 +31,6 @@ import com.vitorpamplona.quartz.nip01Core.core.fastAny import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/tags/RoomIdTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/tags/RoomIdTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/tags/RoomIdTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/tags/RoomIdTag.kt index 382fd64d9a..16266ae1bb 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/tags/RoomIdTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/ephemChat/list/tags/RoomIdTag.kt @@ -30,7 +30,6 @@ class RoomIdTag { companion object { const val TAG_NAME = "group" - @JvmStatic fun parse(tag: Array): RoomId? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -41,19 +40,16 @@ class RoomIdTag { return RoomId(tag[1], relay) } - @JvmStatic fun assemble( id: String, relayUrl: String, ) = arrayOf(TAG_NAME, id, relayUrl) - @JvmStatic fun assemble( id: String, relay: NormalizedRelayUrl, ) = assemble(id, relay.url) - @JvmStatic fun assemble(id: RoomId) = arrayOf(TAG_NAME, id.id, id.relayUrl.url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/forks/BaseThreadedEventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/forks/BaseThreadedEventExt.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/forks/BaseThreadedEventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/forks/BaseThreadedEventExt.kt index 42ac888f3e..0d38a4f5bc 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/forks/BaseThreadedEventExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/forks/BaseThreadedEventExt.kt @@ -20,8 +20,8 @@ */ package com.vitorpamplona.quartz.experimental.forks +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/forks/MarkedETagExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/forks/MarkedETagExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/forks/MarkedETagExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/forks/MarkedETagExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/inlineMetadata/Nip54InlineMetadata.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/inlineMetadata/Nip54InlineMetadata.kt similarity index 73% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/inlineMetadata/Nip54InlineMetadata.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/inlineMetadata/Nip54InlineMetadata.kt index 9ea77f2a92..53307f0b91 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/inlineMetadata/Nip54InlineMetadata.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/inlineMetadata/Nip54InlineMetadata.kt @@ -20,9 +20,8 @@ */ package com.vitorpamplona.quartz.experimental.inlineMetadata -import java.net.URI -import java.net.URLDecoder -import java.net.URLEncoder +import com.vitorpamplona.quartz.utils.UriParser +import com.vitorpamplona.quartz.utils.UrlEncoder import kotlin.coroutines.cancellation.CancellationException class Nip54InlineMetadata { @@ -30,16 +29,25 @@ class Nip54InlineMetadata { url: String, tags: Map>, ): String { + var firstTime = true val extension = - tags - .mapNotNull { + buildString { + tags.forEach { val value = it.value.firstOrNull() if (it.key != "url" && value != null) { - "${it.key}=${URLEncoder.encode(value, "utf-8")}" + if (firstTime) { + firstTime = false + } else { + append("&") + } + append(it.key) + append("=") + append(UrlEncoder.encode(value)) } else { null } - }.joinToString("&") + } + } return if (url.contains("#")) { "$url&$extension" @@ -50,19 +58,9 @@ class Nip54InlineMetadata { fun parse(url: String): Map = try { - fragments(URI(url)) + UriParser(url).fragments() } catch (e: Exception) { if (e is CancellationException) throw e emptyMap() } - - private fun fragments(uri: URI): Map { - if (uri.rawFragment == null) return emptyMap() - return uri.rawFragment.split('&').associate { keyValuePair -> - val parts = keyValuePair.split('=') - val name = parts.firstOrNull() ?: "" - val value = parts.getOrNull(1)?.let { URLDecoder.decode(it, "UTF-8") } ?: "" - Pair(name, value) - } - } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryBaseEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryBaseEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryBaseEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryBaseEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryPrologueEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryPrologueEvent.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryPrologueEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryPrologueEvent.kt index 536c8bb2c0..c7cd84919e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryPrologueEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryPrologueEvent.kt @@ -21,13 +21,13 @@ package com.vitorpamplona.quartz.experimental.interactiveStories import com.vitorpamplona.quartz.experimental.interactiveStories.tags.StoryOptionTag +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip22Comments.RootScope import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt index 1d5725f0fc..9b8a5604af 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStoryReadingStateEvent.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.quartz.experimental.interactiveStories import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.experimental.interactiveStories.tags.ReadStatusTag import com.vitorpamplona.quartz.experimental.interactiveStories.tags.RootSceneTag +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder @@ -30,9 +31,8 @@ import com.vitorpamplona.quartz.nip01Core.core.builder import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip23LongContent.tags.ImageTag import com.vitorpamplona.quartz.nip23LongContent.tags.TitleTag import com.vitorpamplona.quartz.nip31Alts.alt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStorySceneEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStorySceneEvent.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStorySceneEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStorySceneEvent.kt index 4826f08cf0..562e5f3071 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStorySceneEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/InteractiveStorySceneEvent.kt @@ -21,12 +21,12 @@ package com.vitorpamplona.quartz.experimental.interactiveStories import com.vitorpamplona.quartz.experimental.interactiveStories.tags.StoryOptionTag +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip22Comments.RootScope import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/TagArrayBuilderExt.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/TagArrayBuilderExt.kt index b2f0c581a8..3af417f06c 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/TagArrayBuilderExt.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.quartz.experimental.interactiveStories import com.vitorpamplona.quartz.experimental.interactiveStories.tags.ReadStatusTag import com.vitorpamplona.quartz.experimental.interactiveStories.tags.StoryOptionTag import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip23LongContent.tags.ImageTag import com.vitorpamplona.quartz.nip23LongContent.tags.PublishedAtTag import com.vitorpamplona.quartz.nip23LongContent.tags.SummaryTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/ReadStatusTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/ReadStatusTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/ReadStatusTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/ReadStatusTag.kt index 3a90c552e5..838038e690 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/ReadStatusTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/ReadStatusTag.kt @@ -38,7 +38,6 @@ class ReadStatusTag { companion object { const val TAG_NAME = "status" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -46,7 +45,6 @@ class ReadStatusTag { return tag[1] } - @JvmStatic fun assemble(status: STATUS) = arrayOf(TAG_NAME, status.value) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/RootSceneTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/RootSceneTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/RootSceneTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/RootSceneTag.kt index 7586b058d9..3e55232b98 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/RootSceneTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/RootSceneTag.kt @@ -21,11 +21,11 @@ package com.vitorpamplona.quartz.experimental.interactiveStories.tags import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.ensure @@ -68,7 +68,6 @@ data class RootSceneTag( dTag: String, ) = Address.assemble(kind, pubKeyHex, dTag) - @JvmStatic fun parse(tag: Array): RootSceneTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -78,13 +77,11 @@ data class RootSceneTag( return RootSceneTag(address.kind, address.pubKeyHex, address.dTag, hint) } - @JvmStatic fun assemble( aTagId: HexKey, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, aTagId, relay?.url) - @JvmStatic fun assemble( kind: Int, pubKeyHex: String, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/StoryOptionTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/StoryOptionTag.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/StoryOptionTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/StoryOptionTag.kt index 7465ef4663..ba8445036a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/StoryOptionTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/interactiveStories/tags/StoryOptionTag.kt @@ -20,8 +20,8 @@ */ package com.vitorpamplona.quartz.experimental.interactiveStories.tags +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.has -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip46RemoteSigner.getOrNull import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.ensure @@ -36,7 +36,6 @@ class StoryOptionTag( companion object { const val TAG_NAME = "option" - @JvmStatic fun parse(tag: Array): StoryOptionTag? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -45,7 +44,6 @@ class StoryOptionTag( return StoryOptionTag(tag[1], address, tag.getOrNull(3)) } - @JvmStatic fun assemble( title: String, address: Address, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/limits/LimitProcessor.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/limits/LimitProcessor.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/limits/LimitProcessor.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/limits/LimitProcessor.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/limits/Limits.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/limits/Limits.kt similarity index 50% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/limits/Limits.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/limits/Limits.kt index 75904c921f..3c3facf3b3 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/limits/Limits.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/limits/Limits.kt @@ -20,23 +20,25 @@ */ package com.vitorpamplona.quartz.experimental.limits -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +@Serializable class Limits( - @field:JsonProperty("can_write") val canWrite: Boolean?, - @field:JsonProperty("can_read") val canRead: Boolean?, - @field:JsonProperty("accepted_event_kinds") val acceptedEventKinds: Set?, - @field:JsonProperty("blocked_event_kinds") val blockedEventKinds: Set?, - @field:JsonProperty("min_pow_difficulty") val minPoW: Int?, - @field:JsonProperty("max_message_length") val maxMessageLength: Int?, - @field:JsonProperty("max_subscriptions") val maxSubscriptions: Int?, - @field:JsonProperty("max_filters") val maxFilters: Int?, - @field:JsonProperty("max_limit") val maxLimit: Int?, - @field:JsonProperty("max_event_tags") val maxEventTags: Int?, - @field:JsonProperty("max_content_length") val maxContentLength: Int?, - @field:JsonProperty("created_at_msecs_ago") val createdAtMillisecsAgo: Long?, - @field:JsonProperty("created_at_msecs_ahead") val createdAtMillisecsAhead: Long?, - @field:JsonProperty("filter_rate_limit") val filterRateLimit: Long?, - @field:JsonProperty("publishing_rate_limit") val publishingRateLimit: Long?, - @field:JsonProperty("required_tags") val requiredTags: Array>?, + @SerialName("can_write") val canWrite: Boolean?, + @SerialName("can_read") val canRead: Boolean?, + @SerialName("accepted_event_kinds") val acceptedEventKinds: Set?, + @SerialName("blocked_event_kinds") val blockedEventKinds: Set?, + @SerialName("min_pow_difficulty") val minPoW: Int?, + @SerialName("max_message_length") val maxMessageLength: Int?, + @SerialName("max_subscriptions") val maxSubscriptions: Int?, + @SerialName("max_filters") val maxFilters: Int?, + @SerialName("max_limit") val maxLimit: Int?, + @SerialName("max_event_tags") val maxEventTags: Int?, + @SerialName("max_content_length") val maxContentLength: Int?, + @SerialName("created_at_msecs_ago") val createdAtMillisecsAgo: Long?, + @SerialName("created_at_msecs_ahead") val createdAtMillisecsAhead: Long?, + @SerialName("filter_rate_limit") val filterRateLimit: Long?, + @SerialName("publishing_rate_limit") val publishingRateLimit: Long?, + @SerialName("required_tags") val requiredTags: Array>?, ) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/medical/FhirResourceEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/medical/FhirResourceEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/medical/FhirResourceEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/medical/FhirResourceEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/data/FileStorageEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/data/FileStorageEvent.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/data/FileStorageEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/data/FileStorageEvent.kt index 673808088a..6a1a46a770 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/data/FileStorageEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/data/FileStorageEvent.kt @@ -28,7 +28,7 @@ import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.utils.TimeUtils -import java.util.Base64 +import kotlin.io.encoding.Base64 @Immutable class FileStorageEvent( @@ -47,9 +47,9 @@ class FileStorageEvent( const val KIND = 1064 const val ALT = "Binary data" - fun decode(content: String): ByteArray? = runCatching { Base64.getDecoder().decode(content) }.getOrNull() + fun decode(content: String): ByteArray? = runCatching { Base64.decode(content) }.getOrNull() - fun encode(bytes: ByteArray): String = Base64.getEncoder().encodeToString(bytes) + fun encode(bytes: ByteArray): String = Base64.encode(bytes) fun build( data: ByteArray, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/data/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/data/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/data/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/data/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/header/FileStorageHeaderEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/header/FileStorageHeaderEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/header/FileStorageHeaderEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/header/FileStorageHeaderEvent.kt index f026191fe4..cb11e74764 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/header/FileStorageHeaderEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/header/FileStorageHeaderEvent.kt @@ -30,6 +30,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.events.eTag +import com.vitorpamplona.quartz.nip01Core.tags.events.toETag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip94FileMetadata.tags.BlurhashTag import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/header/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/header/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/header/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nip95/header/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nns/NNSEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nns/NNSEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nns/NNSEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nns/NNSEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nns/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nns/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nns/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nns/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/IPv4Tag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/IPv4Tag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/IPv4Tag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/IPv4Tag.kt index c60869fdf9..2b738fc0f2 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/IPv4Tag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/IPv4Tag.kt @@ -27,7 +27,6 @@ class IPv4Tag { companion object { const val TAG_NAME = "ip4" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class IPv4Tag { return tag[1] } - @JvmStatic fun assemble(ip: String) = arrayOf(TAG_NAME, ip) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/IPv6Tag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/IPv6Tag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/IPv6Tag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/IPv6Tag.kt index aecc10fa5a..a3111ca3d9 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/IPv6Tag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/IPv6Tag.kt @@ -27,7 +27,6 @@ class IPv6Tag { companion object { const val TAG_NAME = "ip6" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class IPv6Tag { return tag[1] } - @JvmStatic fun assemble(ip: String) = arrayOf(TAG_NAME, ip) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/VersionTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/VersionTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/VersionTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/VersionTag.kt index 6618467a47..9d2f0c63fc 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/VersionTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/nns/tags/VersionTag.kt @@ -27,7 +27,6 @@ class VersionTag { companion object { const val TAG_NAME = "version" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class VersionTag { return tag[1] } - @JvmStatic fun assemble(ip: String) = arrayOf(TAG_NAME, ip) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/GalleryListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/GalleryListEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/GalleryListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/GalleryListEvent.kt index a6af5d84e0..f31b4d5f52 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/GalleryListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/GalleryListEvent.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.quartz.experimental.profileGallery import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/ProfileGalleryEntryEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/ProfileGalleryEntryEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/ProfileGalleryEntryEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/ProfileGalleryEntryEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/profileGallery/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/PublicMessageEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/PublicMessageEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/PublicMessageEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/PublicMessageEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/tags/ReceiverTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/tags/ReceiverTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/tags/ReceiverTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/tags/ReceiverTag.kt index 7378e2086e..2b90006291 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/tags/ReceiverTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/publicMessages/tags/ReceiverTag.kt @@ -53,7 +53,6 @@ class ReceiverTag( key: HexKey, ): Boolean = tag.has(1) && tag[0] == TAG_NAME && tag[1] == key - @JvmStatic fun parse(tag: Tag): ReceiverTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -64,7 +63,6 @@ class ReceiverTag( return ReceiverTag(tag[1], hint) } - @JvmStatic fun parseKey(tag: Tag): HexKey? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -72,7 +70,6 @@ class ReceiverTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Tag): PubKeyHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -86,7 +83,6 @@ class ReceiverTag( return PubKeyHint(tag[1], hint) } - @JvmStatic fun assemble( pubkey: HexKey, relayHint: NormalizedRelayUrl?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/ContactCardEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/ContactCardEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/ContactCardEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/ContactCardEvent.kt index 0492a26b0f..cbeb2fe222 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/ContactCardEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/ContactCardEvent.kt @@ -28,7 +28,7 @@ import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.core.tagArray import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent import com.vitorpamplona.quartz.nip51Lists.encryption.PrivateTagsInContent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/PetNameTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/PetNameTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/PetNameTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/PetNameTag.kt index 32561ccd62..fa3c2ac0b3 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/PetNameTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/PetNameTag.kt @@ -27,7 +27,6 @@ class PetNameTag { companion object { const val TAG_NAME = "petname" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class PetNameTag { return tag[1] } - @JvmStatic fun assemble(petName: String) = arrayOf(TAG_NAME, petName) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/RankTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/RankTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/RankTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/RankTag.kt index d543c46584..ce6f74e4a0 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/RankTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/RankTag.kt @@ -27,7 +27,6 @@ class RankTag { companion object { const val TAG_NAME = "rank" - @JvmStatic fun parse(tag: Array): Int? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class RankTag { return tag[1].toIntOrNull() } - @JvmStatic fun assemble(rank: Int) = arrayOf(TAG_NAME, rank.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/SummaryTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/SummaryTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/SummaryTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/SummaryTag.kt index 7a78014e69..76d6342ed0 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/SummaryTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/relationshipStatus/tags/SummaryTag.kt @@ -27,7 +27,6 @@ class SummaryTag { companion object { const val TAG_NAME = "summary" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class SummaryTag { return tag[1] } - @JvmStatic fun assemble(ip: String) = arrayOf(TAG_NAME, ip) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/PollNoteEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/PollNoteEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/PollNoteEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/PollNoteEvent.kt index 3c9d165854..d81311e44b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/PollNoteEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/PollNoteEvent.kt @@ -35,7 +35,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/ClosedAtTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/ClosedAtTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/ClosedAtTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/ClosedAtTag.kt index f788d32123..4f626db662 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/ClosedAtTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/ClosedAtTag.kt @@ -27,7 +27,6 @@ class ClosedAtTag { companion object { const val TAG_NAME = "closed_at" - @JvmStatic fun parse(tag: Array): Long? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class ClosedAtTag { return tag[1].toLongOrNull() } - @JvmStatic fun assemble(timestamp: Long) = arrayOf(TAG_NAME, timestamp.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/ConsensusThresholdTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/ConsensusThresholdTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/ConsensusThresholdTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/ConsensusThresholdTag.kt index 175bc05fd6..421d14a05b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/ConsensusThresholdTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/ConsensusThresholdTag.kt @@ -28,7 +28,6 @@ class ConsensusThresholdTag { companion object { const val TAG_NAME = "consensus_threshold" - @JvmStatic fun parse(tag: Array): Double? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -36,7 +35,6 @@ class ConsensusThresholdTag { return tag[1].toLongOrNull()?.toDouble()?.div(100) } - @JvmStatic fun assemble(percentage: Double) = arrayOf(TAG_NAME, (round(percentage * 100)).toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/MaximumTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/MaximumTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/MaximumTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/MaximumTag.kt index 94eea5fa79..04b1a0ac86 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/MaximumTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/MaximumTag.kt @@ -27,7 +27,6 @@ class MaximumTag { companion object { const val TAG_NAME = "value_maximum" - @JvmStatic fun parse(tag: Array): Long? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class MaximumTag { return tag[1].toLongOrNull() } - @JvmStatic fun assemble(timestamp: Long) = arrayOf(TAG_NAME, timestamp.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/MinimumTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/MinimumTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/MinimumTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/MinimumTag.kt index 78541c35b0..d287350d39 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/MinimumTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/MinimumTag.kt @@ -27,7 +27,6 @@ class MinimumTag { companion object { const val TAG_NAME = "value_minimum" - @JvmStatic fun parse(tag: Array): Long? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class MinimumTag { return tag[1].toLongOrNull() } - @JvmStatic fun assemble(timestamp: Long) = arrayOf(TAG_NAME, timestamp.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/PollOptionTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/PollOptionTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/PollOptionTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/PollOptionTag.kt index f22468c2da..1e327efb0d 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/PollOptionTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/experimental/zapPolls/tags/PollOptionTag.kt @@ -32,7 +32,6 @@ class PollOptionTag( companion object { const val TAG_NAME = "poll_option" - @JvmStatic fun parse(tag: Array): PollOptionTag? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -44,7 +43,6 @@ class PollOptionTag( return PollOptionTag(index, tag[2]) } - @JvmStatic fun assemble( index: Int, descriptor: String, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/lightning/LnInvoiceUtil.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/lightning/LnInvoiceUtil.kt similarity index 89% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/lightning/LnInvoiceUtil.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/lightning/LnInvoiceUtil.kt index d800d8eb80..d72f8e6dd3 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/lightning/LnInvoiceUtil.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/lightning/LnInvoiceUtil.kt @@ -20,14 +20,12 @@ */ package com.vitorpamplona.quartz.lightning -import java.math.BigDecimal -import java.util.Locale -import java.util.regex.Pattern +import com.vitorpamplona.quartz.utils.BigDecimal /** based on litecoinj */ object LnInvoiceUtil { private val invoicePattern = - Pattern.compile("lnbc((\\d+)([munp])?)?1[^1\\s]+", Pattern.CASE_INSENSITIVE) + Regex("lnbc((\\d+)([munp])?)?1[^1\\s]+", RegexOption.IGNORE_CASE) /** The Bech32 character set for encoding. */ private const val CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" @@ -200,8 +198,10 @@ object LnInvoiceUtil { ): Boolean { val hrpExpanded: ByteArray = expandHrp(hrp) val combined = ByteArray(hrpExpanded.size + values.size) - System.arraycopy(hrpExpanded, 0, combined, 0, hrpExpanded.size) - System.arraycopy(values, 0, combined, hrpExpanded.size, values.size) + // System.arraycopy(hrpExpanded, 0, combined, 0, hrpExpanded.size) + hrpExpanded.copyInto(combined, 0, 0, hrpExpanded.size) + // System.arraycopy(values, 0, combined, hrpExpanded.size, values.size) + values.copyInto(combined, hrpExpanded.size, 0, values.size) return polymod(combined) == 1 } @@ -238,7 +238,7 @@ object LnInvoiceUtil { } values[i] = CHARSET_REV.get(c.code) } - val hrp = invoice.substring(0, pos).lowercase(Locale.ROOT) + val hrp = invoice.substring(0, pos).lowercase() if (!verifyChecksum(hrp, values)) throw AddressFormatException("Invalid Checksum") return true } @@ -257,12 +257,12 @@ object LnInvoiceUtil { throw IllegalArgumentException("Cannot decode invoice: $invoice", e) } - val matcher = invoicePattern.matcher(invoice) - require(matcher.matches()) { "Failed to match HRP pattern" } - val amountGroup = matcher.group(2) - val multiplierGroup = matcher.group(3) + val matcher = invoicePattern.find(invoice) + require(matcher != null) { "Failed to match HRP pattern" } + val amountGroup = matcher.groups[2]?.value + val multiplierGroup = matcher.groups[3]?.value if (amountGroup == null) { - return BigDecimal.ZERO + return Zero } val amount = BigDecimal(amountGroup) if (multiplierGroup == null) { @@ -274,7 +274,8 @@ object LnInvoiceUtil { return amount.multiply(multiplier(multiplierGroup)) } - val OneHundredK = BigDecimal(100000000) + val Zero = BigDecimal("0") + val OneHundredK = BigDecimal(100_000_000) val OneMili = BigDecimal("0.001") val OneMicro = BigDecimal("0.000001") val OneNano = BigDecimal("0.000000001") @@ -302,12 +303,7 @@ object LnInvoiceUtil { if (input == null) { return null } - val matcher = invoicePattern.matcher(input) - return if (matcher.find()) { - matcher.group() - } else { - null - } + return invoicePattern.find(input)?.value } /** @@ -319,9 +315,9 @@ object LnInvoiceUtil { if (input == null) { return Pair(0, 0) } - val matcher = invoicePattern.matcher(input) - return if (matcher.find()) { - Pair(matcher.start(), matcher.end()) + val matcher = invoicePattern.find(input) + return if (matcher != null) { + Pair(matcher.range.start, matcher.range.endInclusive + 1) } else { Pair(0, 0) } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/lightning/LnWithdrawalUtil.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/lightning/LnWithdrawalUtil.kt similarity index 86% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/lightning/LnWithdrawalUtil.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/lightning/LnWithdrawalUtil.kt index 25d192fe1d..d183ce43c9 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/lightning/LnWithdrawalUtil.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/lightning/LnWithdrawalUtil.kt @@ -20,13 +20,11 @@ */ package com.vitorpamplona.quartz.lightning -import java.util.regex.Pattern - object LnWithdrawalUtil { private val withdrawalPattern = - Pattern.compile( + Regex( "lnurl1[02-9ac-hj-np-z]+", - Pattern.CASE_INSENSITIVE, + RegexOption.IGNORE_CASE, ) /** @@ -40,11 +38,7 @@ object LnWithdrawalUtil { if (input == null) { return null } - val matcher = withdrawalPattern.matcher(input) - return if (matcher.find()) { - matcher.group() - } else { - null - } + val matcher = withdrawalPattern.find(input) + return matcher?.value } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/lightning/Lud06.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/lightning/Lud06.kt similarity index 82% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/lightning/Lud06.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/lightning/Lud06.kt index 4798fb5bc9..002d8aca87 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/lightning/Lud06.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/lightning/Lud06.kt @@ -20,23 +20,22 @@ */ package com.vitorpamplona.quartz.lightning -import android.util.Log import com.vitorpamplona.quartz.nip19Bech32.bech32.Bech32 -import java.util.regex.Pattern +import com.vitorpamplona.quartz.utils.Log class Lud06 { companion object { - val LNURLP_PATTERN = Pattern.compile("(?i:http|https):\\/\\/((.+)\\/)*\\.well-known\\/lnurlp\\/(.*)") + val LNURLP_PATTERN = Regex("(?i:http|https):\\/\\/((.+)\\/)*\\.well-known\\/lnurlp\\/(.*)") } fun toLud16(str: String): String? { return try { val url = toLnUrlp(str) ?: return null - val matcher = LNURLP_PATTERN.matcher(url) - if (matcher.find()) { - val domain = matcher.group(2) - val username = matcher.group(3) + val matcher = LNURLP_PATTERN.find(url) + if (matcher != null) { + val domain = matcher.groups[2]?.value + val username = matcher.groups[3]?.value "$username@$domain" } else { @@ -51,7 +50,7 @@ class Lud06 { fun toLnUrlp(str: String): String? = try { - String(Bech32.decodeBytes(str, false).second) + Bech32.decodeBytes(str, false).second.decodeToString() } catch (t: Throwable) { t.printStackTrace() Log.w("Lud06ToLud16", "Fail to convert LUD06 to LUD16", t) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.kt new file mode 100644 index 0000000000..dca489a28a --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.kt @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.core + +expect class Address( + kind: Kind, + pubKeyHex: HexKey, + dTag: String = "", +) : Comparable
{ + val kind: Kind + val pubKeyHex: HexKey + val dTag: String + + override fun compareTo(other: Address): Int + + fun toValue(): String + + fun countMemory(): Int + + companion object { + fun assemble( + kind: Int, + pubKeyHex: HexKey, + dTag: String = "", + ): String + + fun parse(addressId: String): Address? + + fun isOfKind( + addressId: String, + kind: String, + ): Boolean + } +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressSerializer.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressSerializer.kt new file mode 100644 index 0000000000..0e3ec2490e --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressSerializer.kt @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.core + +import com.vitorpamplona.quartz.nip19Bech32.Nip19Parser +import com.vitorpamplona.quartz.nip19Bech32.entities.NAddress +import com.vitorpamplona.quartz.utils.Hex +import com.vitorpamplona.quartz.utils.Log + +class AddressSerializer { + companion object { + fun assemble( + kind: Int, + pubKeyHex: HexKey, + dTag: String = "", + ) = "$kind:$pubKeyHex:$dTag" + + fun parse(addressId: String): Address? { + if (addressId.isBlank()) return null + return try { + val parts = addressId.split(":", limit = 3) + if (parts.size > 2 && parts[1].length == 64 && Hex.isHex(parts[1])) { + Address(parts[0].toInt(), parts[1], parts.getOrNull(2) ?: "") + } else { + if (addressId.startsWith("naddr1")) { + val addr = Nip19Parser.uriToRoute(addressId)?.entity + if (addr is NAddress) { + addr.address() + } else { + Log.w("AddressableId", "Error parsing. naddr1 seems invalid: $addressId") + null + } + } else { + Log.w("AddressableId", "Error parsing. Not a valid address: $addressId") + null + } + } + } catch (t: Throwable) { + Log.e("AddressableId", "Error parsing: $addressId: ${t.message}", t) + null + } + } + + fun isOfKind( + addressId: String, + kind: String, + ) = addressId.startsWith(kind) && addressId[kind.length] == ':' + } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressableEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressableEvent.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressableEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressableEvent.kt index c59f5b0192..cb81713a42 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressableEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/AddressableEvent.kt @@ -22,8 +22,7 @@ package com.vitorpamplona.quartz.nip01Core.core import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag @Immutable interface AddressableEvent : IEvent { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt similarity index 90% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt index cf857f66c8..8587a707ff 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseAddressableEvent.kt @@ -22,9 +22,8 @@ package com.vitorpamplona.quartz.nip01Core.core import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag @Immutable open class BaseAddressableEvent( diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt similarity index 87% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt index 8f520077bc..8399639c44 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/BaseReplaceableEvent.kt @@ -22,8 +22,7 @@ package com.vitorpamplona.quartz.nip01Core.core import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag @Immutable open class BaseReplaceableEvent( @@ -39,12 +38,12 @@ open class BaseReplaceableEvent( override fun aTag(relayHint: NormalizedRelayUrl?) = ATag(kind, pubKey, FIXED_D_TAG, relayHint) - override fun address() = Address(kind, pubKey, dTag()) + override fun address(): Address = Address(kind, pubKey, dTag()) /** * Creates the tag in a memory efficient way (without creating the ATag class */ - override fun addressTag() = Address.assemble(kind, pubKey, dTag()) + override fun addressTag(): String = AddressSerializer.assemble(kind, pubKey, dTag()) companion object { const val FIXED_D_TAG = "" diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Event.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Event.kt similarity index 89% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Event.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Event.kt index 7a6a2f8d62..40656a0336 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Event.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Event.kt @@ -20,11 +20,9 @@ */ package com.vitorpamplona.quartz.nip01Core.core -import android.util.Log import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.jackson.EventManualSerializer -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.pointerSizeInBytes @@ -38,7 +36,8 @@ open class Event( val tags: TagArray, val content: String, val sig: HexKey, -) : IEvent { +) : IEvent, + OptimizedSerializable { /** * Set this to true if the .content is encrypted or encoded in a * way that it should not be indexed for local search. @@ -56,10 +55,10 @@ open class Event( content.bytesUsedInMemory() + sig.bytesUsedInMemory() - fun toJson(): String = EventManualSerializer.toJson(id, pubKey, createdAt, kind, tags, content, sig) + fun toJson(): String = OptimizedJsonMapper.toJson(this) companion object { - fun fromJson(json: String): Event = JsonMapper.fromJson(json) + fun fromJson(json: String): Event = OptimizedJsonMapper.fromJson(json) fun fromJsonOrNull(json: String) = try { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/HexKey.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/HexKey.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/HexKey.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/HexKey.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/IEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/IEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/IEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/IEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/ImmutableListOfLists.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/ImmutableListOfLists.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/ImmutableListOfLists.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/ImmutableListOfLists.kt index 9e0d353f71..bf0b29d39b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/ImmutableListOfLists.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/ImmutableListOfLists.kt @@ -18,7 +18,7 @@ * 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.quartz.nip02FollowList +package com.vitorpamplona.quartz.nip01Core.core import androidx.compose.runtime.Stable diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Kind.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Kind.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Kind.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Kind.kt diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/OptimizedJsonMapper.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/OptimizedJsonMapper.kt new file mode 100644 index 0000000000..2928a48dfd --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/OptimizedJsonMapper.kt @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.core + +import kotlinx.serialization.json.Json + +interface OptimizedSerializable + +expect object OptimizedJsonMapper { + fun fromJson(json: String): Event + + fun toJson(event: Event): String + + fun fromJsonToTagArray(json: String): Array> + + fun toJson(tags: Array>): String + + inline fun fromJsonTo(json: String): T + + fun toJson(value: OptimizedSerializable): String +} + +object JsonMapper { + val jsonInstance = + Json { + ignoreUnknownKeys = true + } + + inline fun fromJson(json: String): T = jsonInstance.decodeFromString(json) + + inline fun toJson(obj: T): String = jsonInstance.encodeToString(obj) +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Tag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Tag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Tag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Tag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt index f8b8a9926f..435f853cef 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt @@ -113,12 +113,12 @@ fun TagArray.mapValueTagged( } /** - * Returns the first tag value that match the given [tagName] and have a tag value. + * Returns the first tag value that match the given [key] and have a tag value. */ fun TagArray.firstTagValue(key: String) = this.fastFirstOrNull { it.size > 1 && it[0] == key }?.let { it[1] } /** - * Returns the first tag value that match the given [tagName] and have a tag value as long + * Returns the first tag value that match the given [key] and have a tag value as long */ fun TagArray.firstTagValueAsLong(key: String) = this.fastFirstOrNull { it.size > 1 && it[0] == key }?.let { it[1].toLongOrNull() } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/TagArrayBuilder.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/TagArrayBuilder.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/TagArrayBuilder.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/TagArrayBuilder.kt index bfe3f9d6fc..1ca19fdca9 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/TagArrayBuilder.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/TagArrayBuilder.kt @@ -35,7 +35,7 @@ class TagArrayBuilder { tagName: String, tagValue: String, ): TagArrayBuilder { - tagList[tagName]?.removeIf { it.valueOrNull() == tagValue } + tagList[tagName]?.removeAll { it.valueOrNull() == tagValue } if (tagList[tagName]?.isEmpty() == true) { tagList.remove(tagName) } @@ -47,7 +47,7 @@ class TagArrayBuilder { toCompare: Tag, ): TagArrayBuilder { val tagName = toCompare.nameOrNull() ?: return this - tagList[tagName]?.removeIf { predicate(it, toCompare) } + tagList[tagName]?.removeAll { predicate(it, toCompare) } if (tagList[tagName]?.isEmpty() == true) { tagList.remove(tagName) } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/DeterministicSigner.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/DeterministicSigner.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/DeterministicSigner.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/DeterministicSigner.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventAssembler.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventAssembler.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventAssembler.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventAssembler.kt index b6fd97e0f5..abf1da1b24 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventAssembler.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventAssembler.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.quartz.nip01Core.crypto -import com.vitorpamplona.quartz.EventFactory import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.toHexKey +import com.vitorpamplona.quartz.utils.EventFactory import com.vitorpamplona.quartz.utils.RandomInstance class EventAssembler { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventExt.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventExt.kt index a5cd423e0e..4bf0270a9a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/EventExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventExt.kt @@ -18,13 +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.quartz.nip01Core +package com.vitorpamplona.quartz.nip01Core.crypto -import android.util.Log import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.crypto.EventHasher -import com.vitorpamplona.quartz.nip01Core.crypto.Nip01 import com.vitorpamplona.quartz.utils.Hex +import com.vitorpamplona.quartz.utils.Log fun Event.generateId(): String = EventHasher.hashId(pubKey, createdAt, kind, tags, content) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasher.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasher.kt new file mode 100644 index 0000000000..df36449fe9 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasher.kt @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.crypto + +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.toHexKey +import com.vitorpamplona.quartz.utils.Hex +import com.vitorpamplona.quartz.utils.sha256.sha256 + +class EventHasher { + companion object { + fun hashIdBytes( + pubKey: HexKey, + createdAt: Long, + kind: Int, + tags: Array>, + content: String, + ): ByteArray = sha256(EventHasherSerializer.fastMakeJsonForId(pubKey, createdAt, kind, tags, content)) + + fun hashId(serializedJsonAsBytes: ByteArray): String = sha256(serializedJsonAsBytes).toHexKey() + + fun hashId( + pubKey: HexKey, + createdAt: Long, + kind: Int, + tags: Array>, + content: String, + ): String = hashIdBytes(pubKey, createdAt, kind, tags, content).toHexKey() + + fun hashIdEquals( + id: HexKey, + pubKey: HexKey, + createdAt: Long, + kind: Int, + tags: Array>, + content: String, + ): Boolean { + val outId = hashIdBytes(pubKey, createdAt, kind, tags, content) + return Hex.isEqual(id, outId) + } + } +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasherSerializer.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasherSerializer.kt new file mode 100644 index 0000000000..7864f1ef96 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasherSerializer.kt @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.crypto + +import com.vitorpamplona.quartz.nip01Core.core.HexKey + +/** + * This class converts event properties into the JSON and UTF-8 byte array of that json according to NIP-01 + */ +expect object EventHasherSerializer { + fun makeJsonForId( + pubKey: HexKey, + createdAt: Long, + kind: Int, + tags: Array>, + content: String, + ): String + + fun fastMakeJsonForId( + pubKey: HexKey, + createdAt: Long, + kind: Int, + tags: Array>, + content: String, + ): ByteArray +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/KeyPair.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/KeyPair.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/KeyPair.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/KeyPair.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/Nip01.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/Nip01.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/Nip01.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/Nip01.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/EventHintBundle.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/EventHintBundle.kt similarity index 73% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/EventHintBundle.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/EventHintBundle.kt index 61a95097c5..415d295b24 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/EventHintBundle.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/EventHintBundle.kt @@ -23,12 +23,6 @@ package com.vitorpamplona.quartz.nip01Core.hints import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag -import com.vitorpamplona.quartz.nip01Core.tags.events.ETag -import com.vitorpamplona.quartz.nip01Core.tags.people.PTag -import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag -import com.vitorpamplona.quartz.nip18Reposts.quotes.QEventTag import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.pointerSizeInBytes @@ -51,16 +45,4 @@ data class EventHintBundle( (relay?.url?.bytesUsedInMemory() ?: 0) fun toNEvent(): String = NEvent.create(event.id, event.pubKey, event.kind, relay) - - fun toETag() = ETag(event.id, relay, event.pubKey) - - fun toATag() = ATag(event.kind, event.pubKey, event.dTag(), relay) - - fun toPTag() = PTag(event.pubKey, authorHomeRelay) - - fun toMarkedETag(marker: MarkedETag.MARKER) = MarkedETag(event.id, relay, marker, event.pubKey) - - fun toETagArray() = ETag.assemble(event.id, relay, event.pubKey) - - fun toQTagArray() = QEventTag.assemble(event.id, relay, event.pubKey) } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexer.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexer.kt similarity index 87% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexer.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexer.kt index 99fc4a1c13..77347773ae 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexer.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexer.kt @@ -25,7 +25,7 @@ import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.hints.bloom.BloomFilterMurMur3 import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.isLocalHost -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.utils.cache.LargeCache /** * Instead of having one bloom filter per relay per type, which could create @@ -34,9 +34,14 @@ import com.vitorpamplona.quartz.utils.LargeCache * as seed differentiator in the hash function. */ class HintIndexer { - private val eventHints = BloomFilterMurMur3(10_000_000, 5) - private val addressHints = BloomFilterMurMur3(2_000_000, 5) - private val pubKeyHints = BloomFilterMurMur3(10_000_000, 5) + // 5MB for events + private val eventHints = BloomFilterMurMur3(40_000_000, 10) + + // 875 KB for addresses + private val addressHints = BloomFilterMurMur3(7_000_000, 10) + + // 3.75MB for keys + private val pubKeyHints = BloomFilterMurMur3(30_000_000, 10) private val relayDB = LargeCache() private fun add( @@ -53,7 +58,9 @@ class HintIndexer { private fun getHintsFor( id: ByteArray, bloom: BloomFilterMurMur3, - ) = relayDB.filter { relay, _ -> bloom.mightContain(id, relay.hashCode()) } + ) = relayDB.filter { relay, _ -> + bloom.mightContain(id, relay.hashCode()) + } // -------------------- // Event Host hints @@ -83,11 +90,11 @@ class HintIndexer { fun addAddress( addressId: String, relay: NormalizedRelayUrl, - ) = addAddress(addressId.toByteArray(), relay) + ) = addAddress(addressId.encodeToByteArray(), relay) fun hintsForAddress(addressId: ByteArray) = getHintsFor(addressId, addressHints) - fun hintsForAddress(addressId: String) = hintsForAddress(addressId.toByteArray()) + fun hintsForAddress(addressId: String) = hintsForAddress(addressId.encodeToByteArray()) // -------------------- // PubKeys Outbox hints diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintProviders.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintProviders.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintProviders.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintProviders.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/BitSetExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/BitSetExt.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/BitSetExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/BitSetExt.kt index bb4473c54a..32cce2a94f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/BitSetExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/BitSetExt.kt @@ -20,11 +20,11 @@ */ package com.vitorpamplona.quartz.nip01Core.hints.bloom -import java.util.BitSet +import com.vitorpamplona.quartz.utils.BitSet fun BitSet.printBits() = buildString { for (seed in 0 until size()) { - append(if (this@printBits.get(seed)) "1" else "0") + append(if (this@printBits.get(seed)) '1' else '0') } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/BloomFilterMurMur3.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/BloomFilterMurMur3.kt similarity index 76% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/BloomFilterMurMur3.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/BloomFilterMurMur3.kt index 1ed20707ec..e7308f9352 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/BloomFilterMurMur3.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/BloomFilterMurMur3.kt @@ -20,13 +20,17 @@ */ package com.vitorpamplona.quartz.nip01Core.hints.bloom +import com.vitorpamplona.quartz.utils.BitSet import com.vitorpamplona.quartz.utils.RandomInstance -import java.util.Base64 -import java.util.BitSet -import java.util.concurrent.locks.ReentrantReadWriteLock -import kotlin.concurrent.read -import kotlin.concurrent.write +import com.vitorpamplona.quartz.utils.bitSetValueOf +import kotlin.io.encoding.Base64 +/** + * Info: BitSet is not threadsafe for data consistency, but this + * application of the set doesn't require data consistency since + * it only sets bits to true, instead of flipping them back and + * forth between true and false. + */ class BloomFilterMurMur3( private val size: Int, private val rounds: Int, @@ -34,16 +38,13 @@ class BloomFilterMurMur3( private val commonSalt: Int = RandomInstance.int(), ) { private val hasher = MurmurHash3() - private val lock = ReentrantReadWriteLock() fun add( value: ByteArray, salt: Int = commonSalt, ) { - lock.write { - repeat(rounds) { - bits.set(hash(value, salt + it)) - } + repeat(rounds) { round -> + bits.set(hash(value, salt + round)) } } @@ -51,12 +52,12 @@ class BloomFilterMurMur3( value: ByteArray, salt: Int = commonSalt, ): Boolean { - lock.read { - repeat(rounds) { - if (!bits.get(hash(value, salt + it))) return false + repeat(rounds) { round -> + if (!bits.get(hash(value, salt + round))) { + return false } - return true } + return true } private fun hash( @@ -70,13 +71,13 @@ class BloomFilterMurMur3( companion object { fun encode(f: BloomFilterMurMur3): String { - val bitSetB64 = Base64.getEncoder().encodeToString(f.bits.toByteArray()) + val bitSetB64 = Base64.encode(f.bits.toByteArray()) return "${f.size}:${f.rounds}:$bitSetB64:${f.commonSalt}" } fun decode(encodedStr: String): BloomFilterMurMur3 { val (sizeStr, roundsStr, filterB64, salt) = encodedStr.split(":") - val bitSet = BitSet.valueOf(Base64.getDecoder().decode(filterB64)) + val bitSet = bitSetValueOf(Base64.decode(filterB64)) return BloomFilterMurMur3(sizeStr.toInt(), roundsStr.toInt(), bitSet, salt.toInt()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/MurmurHash3.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/MurmurHash3.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/MurmurHash3.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/bloom/MurmurHash3.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/AddressHint.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/AddressHint.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/AddressHint.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/AddressHint.kt index 9292790a55..d5c30dfba4 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/AddressHint.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/AddressHint.kt @@ -26,5 +26,5 @@ data class AddressHint( val addressId: String, val relay: NormalizedRelayUrl, ) : Hint { - override fun id() = addressId.toByteArray(Charsets.UTF_8) + override fun id() = addressId.encodeToByteArray() } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/EventIdHint.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/EventIdHint.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/EventIdHint.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/EventIdHint.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/Hint.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/Hint.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/Hint.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/Hint.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/PubKeyHint.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/PubKeyHint.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/PubKeyHint.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/hints/types/PubKeyHint.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/MetadataEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/MetadataEvent.kt similarity index 57% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/MetadataEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/MetadataEvent.kt index 037aa2ffe8..e5e6d4c981 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/MetadataEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/MetadataEvent.kt @@ -20,15 +20,11 @@ */ package com.vitorpamplona.quartz.nip01Core.metadata -import android.util.Log -import com.fasterxml.jackson.databind.node.JsonNodeFactory -import com.fasterxml.jackson.databind.node.ObjectNode -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.core.builder -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper import com.vitorpamplona.quartz.nip01Core.metadata.tags.AboutTag import com.vitorpamplona.quartz.nip01Core.metadata.tags.BannerTag import com.vitorpamplona.quartz.nip01Core.metadata.tags.DisplayNameTag @@ -39,6 +35,7 @@ import com.vitorpamplona.quartz.nip01Core.metadata.tags.Nip05Tag import com.vitorpamplona.quartz.nip01Core.metadata.tags.PictureTag import com.vitorpamplona.quartz.nip01Core.metadata.tags.PronounsTag import com.vitorpamplona.quartz.nip01Core.metadata.tags.WebsiteTag +import com.vitorpamplona.quartz.nip01Core.metadata.website import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip21UriScheme.toNostrUri @@ -49,7 +46,14 @@ import com.vitorpamplona.quartz.nip39ExtIdentities.githubClaim import com.vitorpamplona.quartz.nip39ExtIdentities.mastodonClaim import com.vitorpamplona.quartz.nip39ExtIdentities.replaceClaims import com.vitorpamplona.quartz.nip39ExtIdentities.twitterClaim +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils +import com.vitorpamplona.quartz.utils.text +import kotlinx.coroutines.CancellationException +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive class MetadataEvent( id: HexKey, @@ -59,13 +63,21 @@ class MetadataEvent( content: String, sig: HexKey, ) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { - fun contactMetadataJson() = jacksonObjectMapper().readTree(content) as? ObjectNode + fun contactMetadataJson() = + try { + Json.parseToJsonElement(content) as JsonObject + } catch (e: Exception) { + if (e is CancellationException) throw e + Log.w("MetadataEvent", "Content Parse Error: ${toNostrUri()} ${e.message}") + null + } fun contactMetaData() = try { - JsonMapper.mapper.readValue(content, UserMetadata::class.java) + JsonMapper.fromJson(content) } catch (e: Exception) { - Log.w("MetadataEvent", "Content Parse Error: ${toNostrUri()} ${e.localizedMessage}") + if (e is CancellationException) throw e + Log.w("MetadataEvent", "Content Parse Error: ${toNostrUri()} ${e.message}") null } @@ -77,10 +89,16 @@ class MetadataEvent( createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ): EventTemplate { - val metadata = JsonNodeFactory.instance.objectNode() - name?.let { addIfNotBlank(metadata, "name", it.trim()) } - return eventTemplate(KIND, metadata.toString(), createdAt) { + val metadata = mutableMapOf() + name?.let { addIfNotBlank(metadata, "name", it) } + val newJsonObject = JsonObject(metadata) + val content = Json.encodeToString(JsonObject.serializer(), newJsonObject) + + return eventTemplate(KIND, content, createdAt) { alt("User profile for $name") + + updateOrDeleteTagNames(metadata) + initializer() } } @@ -103,33 +121,30 @@ class MetadataEvent( initializer: TagArrayBuilder.() -> Unit = {}, ): EventTemplate { // Tries to not delete any existing attribute that we do not work with. - val currentMetadata = JsonNodeFactory.instance.objectNode() + val currentMetadata = mutableMapOf() - name?.let { addIfNotBlank(currentMetadata, NameTag.TAG_NAME, it.trim()) } - displayName?.let { addIfNotBlank(currentMetadata, DisplayNameTag.TAG_NAME, it.trim()) } - picture?.let { addIfNotBlank(currentMetadata, PictureTag.TAG_NAME, it.trim()) } - banner?.let { addIfNotBlank(currentMetadata, BannerTag.TAG_NAME, it.trim()) } - website?.let { addIfNotBlank(currentMetadata, WebsiteTag.TAG_NAME, it.trim()) } - pronouns?.let { addIfNotBlank(currentMetadata, PronounsTag.TAG_NAME, it.trim()) } - about?.let { addIfNotBlank(currentMetadata, AboutTag.TAG_NAME, it.trim()) } - nip05?.let { addIfNotBlank(currentMetadata, Nip05Tag.TAG_NAME, it.trim()) } - lnAddress?.let { addIfNotBlank(currentMetadata, Lud16Tag.TAG_NAME, it.trim()) } - lnURL?.let { addIfNotBlank(currentMetadata, Lud06Tag.TAG_NAME, it.trim()) } + updateFieldsWeWorkWith( + currentMetadata, + name, + displayName, + picture, + banner, + website, + about, + nip05, + lnAddress, + lnURL, + pronouns, + ) - return eventTemplate(KIND, currentMetadata.toString(), createdAt) { - alt("User profile for ${currentMetadata.get("name")?.asText() ?: "Anonymous"}") + val newJsonObject = JsonObject(currentMetadata) + val content = Json.encodeToString(JsonObject.serializer(), newJsonObject) + + return eventTemplate(KIND, content, createdAt) { + alt("User profile for ${currentMetadata["name"]?.text ?: "Anonymous"}") // For https://github.com/nostr-protocol/nips/pull/1770 - currentMetadata.get(NameTag.TAG_NAME)?.asText()?.let { name(it) } - currentMetadata.get(DisplayNameTag.TAG_NAME)?.asText()?.let { displayName(it) } - currentMetadata.get(PictureTag.TAG_NAME)?.asText()?.let { picture(it) } - currentMetadata.get(BannerTag.TAG_NAME)?.asText()?.let { banner(it) } - currentMetadata.get(WebsiteTag.TAG_NAME)?.asText()?.let { website(it) } - currentMetadata.get(PronounsTag.TAG_NAME)?.asText()?.let { pronouns(it) } - currentMetadata.get(AboutTag.TAG_NAME)?.asText()?.let { about(it) } - currentMetadata.get(Nip05Tag.TAG_NAME)?.asText()?.let { nip05(it) } - currentMetadata.get(Lud16Tag.TAG_NAME)?.asText()?.let { lud16(it) } - currentMetadata.get(Lud06Tag.TAG_NAME)?.asText()?.let { lud06(it) } + updateOrDeleteTagNames(currentMetadata) twitter?.let { twitterClaim(it) } mastodon?.let { mastodonClaim(it) } @@ -161,34 +176,30 @@ class MetadataEvent( initializer: TagArrayBuilder.() -> Unit = {}, ): EventTemplate { // Tries to not delete any existing attribute that we do not work with. - val currentMetadata = latest.contactMetadataJson() ?: JsonNodeFactory.instance.objectNode() + val currentMetadata = latest.contactMetadataJson()?.toMutableMap() ?: mutableMapOf() - name?.let { addIfNotBlank(currentMetadata, NameTag.TAG_NAME, it.trim()) } - displayName?.let { addIfNotBlank(currentMetadata, DisplayNameTag.TAG_NAME, it.trim()) } - picture?.let { addIfNotBlank(currentMetadata, PictureTag.TAG_NAME, it.trim()) } - banner?.let { addIfNotBlank(currentMetadata, BannerTag.TAG_NAME, it.trim()) } - website?.let { addIfNotBlank(currentMetadata, WebsiteTag.TAG_NAME, it.trim()) } - pronouns?.let { addIfNotBlank(currentMetadata, PronounsTag.TAG_NAME, it.trim()) } - about?.let { addIfNotBlank(currentMetadata, AboutTag.TAG_NAME, it.trim()) } - nip05?.let { addIfNotBlank(currentMetadata, Nip05Tag.TAG_NAME, it.trim()) } - lnAddress?.let { addIfNotBlank(currentMetadata, Lud16Tag.TAG_NAME, it.trim()) } - lnURL?.let { addIfNotBlank(currentMetadata, Lud06Tag.TAG_NAME, it.trim()) } + updateFieldsWeWorkWith( + currentMetadata, + name, + displayName, + picture, + banner, + website, + about, + nip05, + lnAddress, + lnURL, + pronouns, + ) + + val newJsonObject = JsonObject(currentMetadata) + val content = Json.encodeToString(JsonObject.serializer(), newJsonObject) val tags = latest.tags.builder { - alt("User profile for ${currentMetadata.get("name")?.asText() ?: "Anonymous"}") + alt("User profile for ${currentMetadata["name"]?.text ?: "Anonymous"}") - // For https://github.com/nostr-protocol/nips/pull/1770 - currentMetadata.get(NameTag.TAG_NAME)?.asText()?.let { name(it) } ?: run { remove(NameTag.TAG_NAME) } - currentMetadata.get(DisplayNameTag.TAG_NAME)?.asText()?.let { displayName(it) } ?: run { remove(DisplayNameTag.TAG_NAME) } - currentMetadata.get(PictureTag.TAG_NAME)?.asText()?.let { picture(it) } ?: run { remove(PictureTag.TAG_NAME) } - currentMetadata.get(BannerTag.TAG_NAME)?.asText()?.let { banner(it) } ?: run { remove(BannerTag.TAG_NAME) } - currentMetadata.get(WebsiteTag.TAG_NAME)?.asText()?.let { website(it) } ?: run { remove(WebsiteTag.TAG_NAME) } - currentMetadata.get(PronounsTag.TAG_NAME)?.asText()?.let { pronouns(it) } ?: run { remove(PronounsTag.TAG_NAME) } - currentMetadata.get(AboutTag.TAG_NAME)?.asText()?.let { about(it) } ?: run { remove(AboutTag.TAG_NAME) } - currentMetadata.get(Nip05Tag.TAG_NAME)?.asText()?.let { nip05(it) } ?: run { remove(Nip05Tag.TAG_NAME) } - currentMetadata.get(Lud16Tag.TAG_NAME)?.asText()?.let { lud16(it) } ?: run { remove(Lud16Tag.TAG_NAME) } - currentMetadata.get(Lud06Tag.TAG_NAME)?.asText()?.let { lud06(it) } ?: run { remove(Lud06Tag.TAG_NAME) } + updateOrDeleteTagNames(currentMetadata) val newClaims = latest.replaceClaims(twitter, mastodon, github) remove(IdentityClaimTag.TAG_NAME) @@ -197,18 +208,57 @@ class MetadataEvent( initializer() } - return EventTemplate(createdAt, KIND, tags, currentMetadata.toString()) + return EventTemplate(createdAt, KIND, tags, content) + } + + private fun updateFieldsWeWorkWith( + currentMetadata: MutableMap, + name: String? = null, + displayName: String? = null, + picture: String? = null, + banner: String? = null, + website: String? = null, + about: String? = null, + nip05: String? = null, + lnAddress: String? = null, + lnURL: String? = null, + pronouns: String? = null, + ) { + name?.let { addIfNotBlank(currentMetadata, NameTag.TAG_NAME, it) } + displayName?.let { addIfNotBlank(currentMetadata, DisplayNameTag.TAG_NAME, it) } + picture?.let { addIfNotBlank(currentMetadata, PictureTag.TAG_NAME, it) } + banner?.let { addIfNotBlank(currentMetadata, BannerTag.TAG_NAME, it) } + website?.let { addIfNotBlank(currentMetadata, WebsiteTag.TAG_NAME, it) } + pronouns?.let { addIfNotBlank(currentMetadata, PronounsTag.TAG_NAME, it) } + about?.let { addIfNotBlank(currentMetadata, AboutTag.TAG_NAME, it) } + nip05?.let { addIfNotBlank(currentMetadata, Nip05Tag.TAG_NAME, it) } + lnAddress?.let { addIfNotBlank(currentMetadata, Lud16Tag.TAG_NAME, it) } + lnURL?.let { addIfNotBlank(currentMetadata, Lud06Tag.TAG_NAME, it) } + } + + // For https://github.com/nostr-protocol/nips/pull/1770 + fun TagArrayBuilder.updateOrDeleteTagNames(currentMetadata: MutableMap) { + currentMetadata[NameTag.TAG_NAME]?.let { name(it.text) } ?: run { remove(NameTag.TAG_NAME) } + currentMetadata[DisplayNameTag.TAG_NAME]?.let { displayName(it.text) } ?: run { remove(DisplayNameTag.TAG_NAME) } + currentMetadata[PictureTag.TAG_NAME]?.let { picture(it.text) } ?: run { remove(PictureTag.TAG_NAME) } + currentMetadata[BannerTag.TAG_NAME]?.let { banner(it.text) } ?: run { remove(BannerTag.TAG_NAME) } + currentMetadata[WebsiteTag.TAG_NAME]?.let { website(it.text) } ?: run { remove(WebsiteTag.TAG_NAME) } + currentMetadata[PronounsTag.TAG_NAME]?.let { pronouns(it.text) } ?: run { remove(PronounsTag.TAG_NAME) } + currentMetadata[AboutTag.TAG_NAME]?.let { about(it.text) } ?: run { remove(AboutTag.TAG_NAME) } + currentMetadata[Nip05Tag.TAG_NAME]?.let { nip05(it.text) } ?: run { remove(Nip05Tag.TAG_NAME) } + currentMetadata[Lud16Tag.TAG_NAME]?.let { lud16(it.text) } ?: run { remove(Lud16Tag.TAG_NAME) } + currentMetadata[Lud06Tag.TAG_NAME]?.let { lud06(it.text) } ?: run { remove(Lud06Tag.TAG_NAME) } } private fun addIfNotBlank( - currentJson: ObjectNode, + currentJson: MutableMap, key: String, value: String, ) { if (value.isBlank() || value == "null") { currentJson.remove(key) } else { - currentJson.put(key, value.trim()) + currentJson.put(key, JsonPrimitive(value.trim())) } } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/UserMetadata.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/UserMetadata.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/UserMetadata.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/UserMetadata.kt index a97e82157b..bfbeb24362 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/UserMetadata.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/UserMetadata.kt @@ -21,17 +21,19 @@ package com.vitorpamplona.quartz.nip01Core.metadata import androidx.compose.runtime.Stable -import com.fasterxml.jackson.annotation.JsonProperty -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable @Stable +@Serializable class UserMetadata { var name: String? = null @Deprecated("Use name instead", replaceWith = ReplaceWith("name")) var username: String? = null - @JsonProperty("display_name") + @SerialName("display_name") var displayName: String? = null var picture: String? = null var banner: String? = null @@ -50,7 +52,8 @@ class UserMetadata { var twitter: String? = null - @Transient + @kotlinx.serialization.Transient + @kotlin.jvm.Transient var tags: ImmutableListOfLists? = null fun anyName(): String? = displayName ?: name ?: username diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/AboutTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/AboutTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/AboutTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/AboutTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/BannerTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/BannerTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/BannerTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/BannerTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/DisplayNameTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/DisplayNameTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/DisplayNameTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/DisplayNameTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Lud06Tag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Lud06Tag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Lud06Tag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Lud06Tag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Lud16Tag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Lud16Tag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Lud16Tag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Lud16Tag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/NameTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/NameTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/NameTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/NameTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Nip05Tag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Nip05Tag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Nip05Tag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/Nip05Tag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/PictureTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/PictureTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/PictureTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/PictureTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/PronounsTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/PronounsTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/PronounsTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/PronounsTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/WebsiteTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/WebsiteTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/WebsiteTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/tags/WebsiteTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/INostrClient.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/INostrClient.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/INostrClient.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/INostrClient.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/NostrClient.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/NostrClient.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/NostrClient.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/NostrClient.kt index 70136be204..adae3512f6 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/NostrClient.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/NostrClient.kt @@ -43,6 +43,7 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.sample import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.sync.Mutex /** * The NostrClient manages Nostr relay operations, subscriptions, and event delivery. It maintains: @@ -136,13 +137,20 @@ class NostrClient( override fun isActive() = isActive - @Synchronized + val myReconnectMutex = Mutex() + override fun reconnect(onlyIfChanged: Boolean) { - if (onlyIfChanged) { - relayPool.reconnectIfNeedsToORIfItIsTime() - } else { - relayPool.disconnect() - relayPool.connect() + if (myReconnectMutex.tryLock()) { + try { + if (onlyIfChanged) { + relayPool.reconnectIfNeedsToORIfItIsTime() + } else { + relayPool.disconnect() + relayPool.connect() + } + } finally { + myReconnectMutex.unlock() + } } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/NostrClientSubscription.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/NostrClientSubscription.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/NostrClientSubscription.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/NostrClientSubscription.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/EventCollector.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/EventCollector.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/EventCollector.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/EventCollector.kt index 79dcfdb180..a3a9c63c6a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/EventCollector.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/EventCollector.kt @@ -20,11 +20,11 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.client.accessories -import android.util.Log import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientListener import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient +import com.vitorpamplona.quartz.utils.Log /** * Listens to NostrClient's onEvent messages for caching purposes. @@ -47,13 +47,13 @@ class EventCollector( } init { - Log.d("${this.javaClass.simpleName}", "Init, Subscribe") + Log.d("EventCollector", "Init, Subscribe") client.subscribe(clientListener) } fun destroy() { // makes sure to run - Log.d("${this.javaClass.simpleName}", "Destroy, Unsubscribe") + Log.d("EventCollector", "Destroy, Unsubscribe") client.unsubscribe(clientListener) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/NostrClientSendAndWaitExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/NostrClientSendAndWaitExt.kt similarity index 55% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/NostrClientSendAndWaitExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/NostrClientSendAndWaitExt.kt index ac499b443f..0fed3c8d11 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/NostrClientSendAndWaitExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/NostrClientSendAndWaitExt.kt @@ -20,16 +20,25 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.client.accessories -import android.util.Log import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientListener import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.RelayState import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.DelicateCoroutinesApi -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO +import kotlinx.coroutines.async +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.withTimeoutOrNull + +class Result( + val relay: NormalizedRelayUrl, + val success: Boolean, +) @OptIn(DelicateCoroutinesApi::class) suspend fun INostrClient.sendAndWaitForResponse( @@ -37,12 +46,9 @@ suspend fun INostrClient.sendAndWaitForResponse( relayList: Set, timeoutInSeconds: Long = 15, ): Boolean { - val size = relayList.size - val latch = CountDownLatch(size) - val relayResults = mutableMapOf() - var result = false + val resultChannel = Channel() - Log.d("sendAndWaitForResponse", "Waiting for $size responses") + Log.d("sendAndWaitForResponse", "Waiting for ${relayList.size} responses") val subscription = object : IRelayClientListener { @@ -51,24 +57,20 @@ suspend fun INostrClient.sendAndWaitForResponse( subId: String, error: Error, ) { - if (relay.url in relayList && relayResults[relay.url] == null) { - relayResults[relay.url] = false - latch.countDown() + if (relay.url in relayList) { + resultChannel.trySend(Result(relay.url, false)) + Log.d("sendAndWaitForResponse", "onError Error from relay ${relay.url} error: $error") } - Log.d("sendAndWaitForResponse", "onError Error from relay ${relay.url} count: ${latch.count} error: $error") } override fun onRelayStateChange( relay: IRelayClient, type: RelayState, ) { - if (type == RelayState.DISCONNECTED) { - if (relay.url in relayList && relayResults[relay.url] == null) { - relayResults[relay.url] = false - latch.countDown() - } + if (type == RelayState.DISCONNECTED && relay.url in relayList) { + resultChannel.trySend(Result(relay.url, false)) + Log.d("sendAndWaitForResponse", "onRelayStateChange ${type.name} from relay ${relay.url}") } - Log.d("sendAndWaitForResponse", "onRelayStateChange ${type.name} from relay ${relay.url} count: ${latch.count}") } override fun onSendResponse( @@ -78,33 +80,45 @@ suspend fun INostrClient.sendAndWaitForResponse( message: String, ) { if (eventId == event.id) { - if (relayResults[relay.url] == null) { - latch.countDown() - relayResults[relay.url] = success - } else { - if (success && relayResults[relay.url] == false) { - relayResults[relay.url] = true - } - } - - if (success) { - result = true - } - - Log.d("sendAndWaitForResponse", "onSendResponse Received response for $eventId from relay ${relay.url} count: ${latch.count} message $message success $success") + resultChannel.trySend(Result(relay.url, success)) + Log.d("sendAndWaitForResponse", "onSendResponse Received response for $eventId from relay ${relay.url} message $message success $success") } } } subscribe(subscription) + // subscribe before sending the result. + val resultSubscription = + coroutineScope { + async(Dispatchers.IO) { + val receivedResults = mutableMapOf() + // The withTimeout block will cancel the coroutine if the loop takes too long + withTimeoutOrNull(timeoutInSeconds * 1000) { + while (receivedResults.size < relayList.size) { + val result = resultChannel.receive() + + val currentResult = receivedResults[result.relay] + // do not override a successful result. + if (currentResult == null || !currentResult) { + receivedResults.put(result.relay, result.success) + } + } + } + receivedResults + } + } + send(event, relayList) - latch.await(timeoutInSeconds, TimeUnit.SECONDS) + val receivedResults = resultSubscription.await() unsubscribe(subscription) - Log.d("sendAndWaitForResponse", "countdown finished") + // Clean up the channel + resultChannel.close() - return result + Log.d("sendAndWaitForResponse", "Finished with ${receivedResults.size} results") + + return receivedResults.any { it.value } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/NostrClientSingleDownloadExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/NostrClientSingleDownloadExt.kt similarity index 82% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/NostrClientSingleDownloadExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/NostrClientSingleDownloadExt.kt index 6f62fb287e..85fc4b4c42 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/NostrClientSingleDownloadExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/NostrClientSingleDownloadExt.kt @@ -27,16 +27,15 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient import com.vitorpamplona.quartz.nip01Core.relay.client.single.newSubId import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.withTimeoutOrNull -fun INostrClient.downloadFirstEvent( +suspend fun INostrClient.downloadFirstEvent( subscriptionId: String = newSubId(), filters: Map>, - onResponse: (Event) -> Unit, -) { +): Event? { + val resultChannel = Channel() + val listener = object : IRelayClientListener { override fun onEvent( @@ -47,9 +46,7 @@ fun INostrClient.downloadFirstEvent( afterEOSE: Boolean, ) { if (subId == subscriptionId) { - unsubscribe(this) - close(subscriptionId) - onResponse(event) + resultChannel.trySend(event) } } } @@ -58,10 +55,14 @@ fun INostrClient.downloadFirstEvent( openReqSubscription(subscriptionId, filters) - GlobalScope.launch(Dispatchers.IO) { - delay(30000) + val result = + withTimeoutOrNull(30000) { + resultChannel.receive() + } - close(subscriptionId) - unsubscribe(listener) - } + close(subscriptionId) + unsubscribe(listener) + resultChannel.close() + + return result } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayAuthenticator.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayAuthenticator.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayAuthenticator.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayAuthenticator.kt index a801f84d02..d7a53b8ad4 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayAuthenticator.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayAuthenticator.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.client.accessories -import android.util.Log import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientListener import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -45,13 +45,13 @@ class RelayAuthenticator( } init { - Log.d("${this.javaClass.simpleName}", "Init, Subscribe") + Log.d("RelayAuthenticator", "Init, Subscribe") client.subscribe(clientListener) } fun destroy() { // makes sure to run - Log.d("${this.javaClass.simpleName}", "Destroy, Unsubscribe") + Log.d("RelayAuthenticator", "Destroy, Unsubscribe") client.unsubscribe(clientListener) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayInsertConfirmationCollector.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayInsertConfirmationCollector.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayInsertConfirmationCollector.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayInsertConfirmationCollector.kt index 6d1050acd1..edbf77f167 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayInsertConfirmationCollector.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayInsertConfirmationCollector.kt @@ -20,11 +20,11 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.client.accessories -import android.util.Log import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientListener import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient +import com.vitorpamplona.quartz.utils.Log /** * Listens to NostrClient's onEvent messages for caching purposes. @@ -48,13 +48,13 @@ class RelayInsertConfirmationCollector( } init { - Log.d("${this.javaClass.simpleName}", "Init, Subscribe") + Log.d("RelayInsertConfirmationCollector", "Init, Subscribe") client.subscribe(clientListener) } fun destroy() { // makes sure to run - Log.d("${this.javaClass.simpleName}", "Destroy, Unsubscribe") + Log.d("RelayInsertConfirmationCollector", "Destroy, Unsubscribe") client.unsubscribe(clientListener) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayLogger.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayLogger.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayLogger.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayLogger.kt index 039ec39160..8bb97f855a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayLogger.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayLogger.kt @@ -20,11 +20,11 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.client.accessories -import android.util.Log import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientListener import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient +import com.vitorpamplona.quartz.utils.Log /** * Listens to NostrClient's onNotify messages from the relay @@ -56,13 +56,13 @@ class RelayLogger( } init { - Log.d("${this.javaClass.simpleName}", "Init, Subscribe") + Log.d("RelayLogger", "Init, Subscribe") client.subscribe(clientListener) } fun destroy() { // makes sure to run - Log.d("${this.javaClass.simpleName}", "Destroy, Unsubscribe") + Log.d("RelayLogger", "Destroy, Unsubscribe") client.unsubscribe(clientListener) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayNotifier.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayNotifier.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayNotifier.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayNotifier.kt index fe33552d24..a646d24145 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayNotifier.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/accessories/RelayNotifier.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.client.accessories -import android.util.Log import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientListener import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient +import com.vitorpamplona.quartz.utils.Log /** * Listens to NostrClient's onNotify messages from the relay @@ -33,7 +33,7 @@ class RelayNotifier( val notify: (message: String, relay: IRelayClient) -> Unit, ) { companion object { - val TAG = RelayNotifier::class.java.simpleName + val TAG = "RelayNotifier" } private val clientListener = diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/listeners/IRelayClientListener.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/listeners/IRelayClientListener.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/listeners/IRelayClientListener.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/listeners/IRelayClientListener.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/listeners/RedirectRelayClientListener.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/listeners/RedirectRelayClientListener.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/listeners/RedirectRelayClientListener.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/listeners/RedirectRelayClientListener.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutbox.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutbox.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutbox.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutbox.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutboxRepository.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutboxRepository.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutboxRepository.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutboxRepository.kt index 8a301109d0..67356b2ed8 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutboxRepository.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolEventOutboxRepository.kt @@ -42,7 +42,7 @@ class PoolEventOutboxRepository { fun activeOutboxCacheFor(url: NormalizedRelayUrl): Set { val myEvents = mutableSetOf() - eventOutbox.forEach { eventId, outboxCache -> + eventOutbox.forEach { (eventId, outboxCache) -> if (url in outboxCache.relays) { myEvents.add(eventId) } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolSubscriptionRepository.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolSubscriptionRepository.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolSubscriptionRepository.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolSubscriptionRepository.kt index 2ac117b69f..62b353a12e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolSubscriptionRepository.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/PoolSubscriptionRepository.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.quartz.nip01Core.relay.client.pool import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.utils.cache.LargeCache import kotlinx.coroutines.flow.MutableStateFlow class PoolSubscriptionRepository { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/RelayBasedFilter.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/RelayBasedFilter.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/RelayBasedFilter.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/RelayBasedFilter.kt index ed0fcfa9c1..ba5b305766 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/RelayBasedFilter.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/RelayBasedFilter.kt @@ -20,9 +20,9 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.client.pool -import android.util.Log import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl +import com.vitorpamplona.quartz.utils.Log /** * Represents a filter that should only be sent to a given relay. diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/RelayPool.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/RelayPool.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/RelayPool.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/RelayPool.kt index 4eb6daa859..9a7a6cebe7 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/RelayPool.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/pool/RelayPool.kt @@ -28,8 +28,8 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.RelayState import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.utils.LargeCache import com.vitorpamplona.quartz.utils.TimeUtils +import com.vitorpamplona.quartz.utils.cache.LargeCache import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/IRelayClient.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/IRelayClient.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/IRelayClient.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/IRelayClient.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/Subscription.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/Subscription.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/Subscription.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/Subscription.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClient.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClient.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClient.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClient.kt index e80d553dbf..27410def9c 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClient.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClient.kt @@ -20,9 +20,9 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.client.single.basic -import android.util.Log import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientListener import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.RelayState import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient @@ -31,12 +31,13 @@ import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.AuthMessage import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.ClosedMessage import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.EoseMessage import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.EventMessage +import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.Message import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.NoticeMessage import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.NotifyMessage import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.OkMessage -import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.ToClientParser import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.AuthCmd import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.CloseCmd +import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.Command import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.CountCmd import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.EventCmd import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.ReqCmd @@ -47,12 +48,14 @@ import com.vitorpamplona.quartz.nip01Core.relay.sockets.WebSocket import com.vitorpamplona.quartz.nip01Core.relay.sockets.WebSocketListener import com.vitorpamplona.quartz.nip01Core.relay.sockets.WebsocketBuilder import com.vitorpamplona.quartz.nip42RelayAuth.RelayAuthEvent +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.bytesUsedInMemory import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import java.util.concurrent.atomic.AtomicBoolean +import kotlin.concurrent.atomics.AtomicBoolean +import kotlin.concurrent.atomics.ExperimentalAtomicApi import kotlin.coroutines.cancellation.CancellationException /** @@ -73,6 +76,7 @@ import kotlin.coroutines.cancellation.CancellationException * - Processes relay messages (e.g., `EVENT`, `EOSE`, `OK`, `AUTH`) and delegates to appropriate callbacks. * - Dispatches received events, notices, and subscription closures via the [listener]. */ +@OptIn(ExperimentalAtomicApi::class) open class BasicRelayClient( override val url: NormalizedRelayUrl, val socketBuilder: WebsocketBuilder, @@ -101,9 +105,7 @@ open class BasicRelayClient( private val authResponseWatcher = mutableMapOf() private val authChallengesSent = mutableSetOf() - private var connectingMutex = AtomicBoolean() - - private val parser = ToClientParser() + private var connectingMutex = AtomicBoolean(false) fun isConnectionStarted(): Boolean = socket != null @@ -125,13 +127,13 @@ open class BasicRelayClient( fun connectAndRunOverride(onConnected: () -> Unit) { // If there is a connection, don't wait. - if (connectingMutex.getAndSet(true)) { + if (connectingMutex.exchange(true)) { return } try { if (socket != null) { - connectingMutex.set(false) + connectingMutex.store(false) return } @@ -145,11 +147,11 @@ open class BasicRelayClient( if (e is CancellationException) throw e Log.w(logTag, "Crash before connecting", e) - stats.newError(e.message ?: "Error trying to connect: ${e.javaClass.simpleName}") + stats.newError(e.message ?: "Error trying to connect: $e") markConnectionAsClosed() } finally { - connectingMutex.set(false) + connectingMutex.store(false) } } @@ -215,7 +217,7 @@ open class BasicRelayClient( } else { // checks if this is an actual failure. Closing the socket generates an onFailure as well. if (!(socket == null && (t.message == "Socket is closed" || t.message == "Socket closed"))) { - stats.newError(response ?: t.message ?: "onFailure event from server: ${t.javaClass.simpleName}") + stats.newError(response ?: t.message ?: "onFailure event from server: $t") } // Failures disconnect the relay. @@ -241,7 +243,7 @@ open class BasicRelayClient( stats.addBytesReceived(text.bytesUsedInMemory()) try { - when (val msg = parser.parse(text)) { + when (val msg = OptimizedJsonMapper.fromJsonTo(text)) { is EventMessage -> processEvent(msg) is EoseMessage -> processEose(msg) is NoticeMessage -> processNotice(msg) @@ -337,10 +339,10 @@ open class BasicRelayClient( } private fun processClosed(msg: ClosedMessage) { - Log.w(logTag, "Relay Closed Subscription ${msg.subscriptionId} ${msg.message}") - stats.newNotice("Subscription closed: ${msg.subscriptionId} ${msg.message}") - afterEOSEPerSubscription[msg.subscriptionId] = false - listener.onClosed(this@BasicRelayClient, msg.subscriptionId, msg.message) + Log.w(logTag, "Relay Closed Subscription ${msg.subId} ${msg.message}") + stats.newNotice("Subscription closed: ${msg.subId} ${msg.message}") + afterEOSEPerSubscription[msg.subId] = false + listener.onClosed(this@BasicRelayClient, msg.subId, msg.message) } private fun processUnknownMessage(newMessage: String) { @@ -375,7 +377,7 @@ open class BasicRelayClient( if (isReady) { if (filters.isNotEmpty()) { afterEOSEPerSubscription[subId] = false - writeToSocket(ReqCmd.Companion.toJson(subId, filters)) + writeToSocket(ReqCmd(subId, filters)) } } } else { @@ -391,7 +393,7 @@ open class BasicRelayClient( if (isReady) { if (filters.isNotEmpty()) { afterEOSEPerSubscription[subId] = false - writeToSocket(CountCmd.Companion.toJson(subId, filters)) + writeToSocket(CountCmd(subId, filters)) } } } else { @@ -400,7 +402,7 @@ open class BasicRelayClient( } override fun connectAndSyncFiltersIfDisconnected() { - if (!isConnectionStarted() && !connectingMutex.get()) { + if (!isConnectionStarted() && !connectingMutex.load()) { // waits 60 seconds to reconnect after disconnected. if (TimeUtils.now() > lastConnectTentativeInSeconds + delayToConnectInSeconds) { upRelayDelayToConnect() @@ -436,20 +438,24 @@ open class BasicRelayClient( if (challenge != null && challenge !in authChallengesSent) { authResponseWatcher[signedEvent.id] = false authChallengesSent.add(challenge) - writeToSocket(AuthCmd.Companion.toJson(signedEvent)) + writeToSocket(AuthCmd(signedEvent)) } } override fun sendEvent(event: Event) { if (isConnectionStarted()) { if (isReady) { - writeToSocket(EventCmd.Companion.toJson(event)) + writeToSocket(EventCmd(event)) } } else { connectAndSyncFiltersIfDisconnected() } } + private fun writeToSocket(cmd: Command) { + writeToSocket(OptimizedJsonMapper.toJson(cmd)) + } + private fun writeToSocket(str: String) { if (socket == null) { listener.onError( @@ -469,7 +475,7 @@ open class BasicRelayClient( override fun close(subscriptionId: String) { // avoids sending closes for subscriptions that were never sent to this relay. if (afterEOSEPerSubscription.containsKey(subscriptionId)) { - writeToSocket(CloseCmd.toJson(subscriptionId)) + writeToSocket(CloseCmd(subscriptionId)) afterEOSEPerSubscription[subscriptionId] = false } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/simple/OutboxCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/simple/OutboxCache.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/simple/OutboxCache.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/simple/OutboxCache.kt index 7d6d581099..263d0dbe20 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/simple/OutboxCache.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/simple/OutboxCache.kt @@ -27,7 +27,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.RedirectRelayCl import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.RelayState import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient import com.vitorpamplona.quartz.nip42RelayAuth.RelayAuthEvent -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.utils.cache.LargeCache class OutboxCache( listener: IRelayClientListener, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/simple/SimpleRelayClient.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/simple/SimpleRelayClient.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/simple/SimpleRelayClient.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/simple/SimpleRelayClient.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/stats/RelayStat.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/stats/RelayStat.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/stats/RelayStat.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/stats/RelayStat.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/stats/RelayStats.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/stats/RelayStats.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/stats/RelayStats.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/stats/RelayStats.kt index a282c9e499..1a8759d7d4 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/stats/RelayStats.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/stats/RelayStats.kt @@ -20,16 +20,16 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.client.stats -import android.util.LruCache +import androidx.collection.LruCache import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl object RelayStats { private val innerCache = object : LruCache(100) { - override fun create(key: NormalizedRelayUrl?) = RelayStat() + override fun create(key: NormalizedRelayUrl): RelayStat = RelayStat() } - fun get(url: NormalizedRelayUrl): RelayStat = innerCache.get(url) + fun get(url: NormalizedRelayUrl): RelayStat = innerCache.get(url) ?: RelayStat() fun addBytesReceived( url: NormalizedRelayUrl, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/Subscription.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/Subscription.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/Subscription.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/Subscription.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/SubscriptionController.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/SubscriptionController.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/SubscriptionController.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/SubscriptionController.kt index 0f6f58aee3..e471d4f178 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/SubscriptionController.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/SubscriptionController.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientLis import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.utils.cache.LargeCache /** * Manages Nostr subscriptions using a [NostrClient], allowing subscriptions to be created, modified, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/SubscriptionStats.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/SubscriptionStats.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/SubscriptionStats.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/SubscriptionStats.kt index 87d01b85eb..246e2cbb94 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/SubscriptionStats.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/subscriptions/SubscriptionStats.kt @@ -20,8 +20,8 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions -import android.util.Log -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.utils.Log +import com.vitorpamplona.quartz.utils.cache.LargeCache class SubscriptionStats { data class Counter( diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/AuthMessage.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/AuthMessage.kt similarity index 86% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/AuthMessage.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/AuthMessage.kt index dc0f83908d..dde960e677 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/AuthMessage.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/AuthMessage.kt @@ -20,18 +20,12 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.commands.toClient -import com.fasterxml.jackson.databind.JsonNode - class AuthMessage( val challenge: String, ) : Message { + override fun label() = LABEL + companion object { const val LABEL = "AUTH" - - @JvmStatic - fun parse(msgArray: JsonNode): AuthMessage = - AuthMessage( - msgArray.get(1).asText(), - ) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/ClosedMessage.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/ClosedMessage.kt similarity index 82% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/ClosedMessage.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/ClosedMessage.kt index 8dbb39194c..30cdd00c5e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/ClosedMessage.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/ClosedMessage.kt @@ -20,20 +20,13 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.commands.toClient -import com.fasterxml.jackson.databind.JsonNode - class ClosedMessage( - val subscriptionId: String, + val subId: String, val message: String, ) : Message { + override fun label() = LABEL + companion object { const val LABEL = "CLOSED" - - @JvmStatic - fun parse(msgArray: JsonNode): ClosedMessage = - ClosedMessage( - msgArray[1].asText(), - msgArray[2].asText(), - ) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/EoseMessage.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/EoseMessage.kt similarity index 86% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/EoseMessage.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/EoseMessage.kt index fd57436ea7..41c2ee90f5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/EoseMessage.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/EoseMessage.kt @@ -20,18 +20,12 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.commands.toClient -import com.fasterxml.jackson.databind.JsonNode - class EoseMessage( val subId: String, ) : Message { + override fun label() = LABEL + companion object { const val LABEL = "EOSE" - - @JvmStatic - fun parse(msgArray: JsonNode): EoseMessage = - EoseMessage( - msgArray.get(1).asText(), - ) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/EventMessage.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/EventMessage.kt similarity index 81% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/EventMessage.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/EventMessage.kt index ee71c2381d..a914aad223 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/EventMessage.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/EventMessage.kt @@ -20,22 +20,15 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.commands.toClient -import com.fasterxml.jackson.databind.JsonNode import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper class EventMessage( val subId: String, val event: Event, ) : Message { + override fun label() = LABEL + companion object { const val LABEL = "EVENT" - - @JvmStatic - fun parse(msgArray: JsonNode): EventMessage = - EventMessage( - msgArray.get(1).asText(), - JsonMapper.fromJson(msgArray.get(2)), - ) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/Message.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/Message.kt similarity index 89% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/Message.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/Message.kt index 4688862392..d859ddc7e8 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/Message.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/Message.kt @@ -20,4 +20,8 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.commands.toClient -interface Message +import com.vitorpamplona.quartz.nip01Core.core.OptimizedSerializable + +interface Message : OptimizedSerializable { + fun label(): String +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/NoticeMessage.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/NoticeMessage.kt similarity index 89% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/NoticeMessage.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/NoticeMessage.kt index ba1ca14997..3f5b4a9b4d 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/NoticeMessage.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/NoticeMessage.kt @@ -20,15 +20,12 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.commands.toClient -import com.fasterxml.jackson.databind.JsonNode - class NoticeMessage( val message: String, ) : Message { + override fun label() = LABEL + companion object { const val LABEL = "NOTICE" - - @JvmStatic - fun parse(msgArray: JsonNode) = NoticeMessage(msgArray.get(1).asText()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/NotifyMessage.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/NotifyMessage.kt similarity index 86% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/NotifyMessage.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/NotifyMessage.kt index cbb42d956b..cb90026b18 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/NotifyMessage.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/NotifyMessage.kt @@ -20,18 +20,12 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.commands.toClient -import com.fasterxml.jackson.databind.JsonNode - class NotifyMessage( val message: String, ) : Message { + override fun label() = LABEL + companion object { const val LABEL = "NOTIFY" - - @JvmStatic - fun parse(msgArray: JsonNode): NotifyMessage = - NotifyMessage( - msgArray.get(1).asText(), - ) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/OkMessage.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/OkMessage.kt similarity index 82% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/OkMessage.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/OkMessage.kt index db6ed62b25..eaf177bedd 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/OkMessage.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/OkMessage.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.commands.toClient -import com.fasterxml.jackson.databind.JsonNode import com.vitorpamplona.quartz.nip01Core.core.HexKey class OkMessage( @@ -28,15 +27,9 @@ class OkMessage( val success: Boolean, val message: String, ) : Message { + override fun label() = LABEL + companion object { const val LABEL = "OK" - - @JvmStatic - fun parse(msgArray: JsonNode): OkMessage = - OkMessage( - msgArray[1].asText(), - msgArray[2].asBoolean(), - if (msgArray.size() > 2) msgArray[3].asText() else "", - ) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/AuthCmd.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/AuthCmd.kt similarity index 77% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/AuthCmd.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/AuthCmd.kt index 95c11e8889..bba274c5a4 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/AuthCmd.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/AuthCmd.kt @@ -20,23 +20,14 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay -import com.fasterxml.jackson.databind.JsonNode -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper import com.vitorpamplona.quartz.nip42RelayAuth.RelayAuthEvent class AuthCmd( val event: RelayAuthEvent, ) : Command { + override fun label(): String = LABEL + companion object { const val LABEL = "AUTH" - - @JvmStatic - fun toJson(authEvent: RelayAuthEvent): String = """["AUTH",${authEvent.toJson()}]""" - - @JvmStatic - fun parse(msgArray: JsonNode): AuthCmd = - AuthCmd( - JsonMapper.fromJson(msgArray.get(1)) as RelayAuthEvent, - ) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CloseCmd.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CloseCmd.kt similarity index 79% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CloseCmd.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CloseCmd.kt index 0bd9d40920..ab57f7a72a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CloseCmd.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CloseCmd.kt @@ -20,21 +20,12 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay -import com.fasterxml.jackson.databind.JsonNode - class CloseCmd( - val subscriptionId: String, + val subId: String, ) : Command { + override fun label(): String = LABEL + companion object { const val LABEL = "CLOSE" - - @JvmStatic - fun toJson(subscriptionId: String): String = """["CLOSE","$subscriptionId"]""" - - @JvmStatic - fun parse(msgArray: JsonNode): CloseCmd = - CloseCmd( - msgArray.get(1).asText(), - ) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/Command.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/Command.kt similarity index 89% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/Command.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/Command.kt index 2184ac62c1..3b04d4c504 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/Command.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/Command.kt @@ -20,4 +20,8 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay -interface Command +import com.vitorpamplona.quartz.nip01Core.core.OptimizedSerializable + +interface Command : OptimizedSerializable { + fun label(): String +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CountCmd.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CountCmd.kt new file mode 100644 index 0000000000..e858fa4391 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CountCmd.kt @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.relay.commands.toRelay + +import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter + +class CountCmd( + val subId: String, + val filters: List, +) : Command { + override fun label(): String = LABEL + + companion object { + const val LABEL = "COUNT" + } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/EventCmd.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/EventCmd.kt similarity index 78% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/EventCmd.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/EventCmd.kt index ea8349a246..73a28a35c5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/EventCmd.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/EventCmd.kt @@ -20,23 +20,14 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay -import com.fasterxml.jackson.databind.JsonNode import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper class EventCmd( val event: Event, ) : Command { + override fun label(): String = LABEL + companion object { const val LABEL = "EVENT" - - @JvmStatic - fun toJson(event: Event): String = """["EVENT",${event.toJson()}]""" - - @JvmStatic - fun parse(msgArray: JsonNode): EventCmd = - EventCmd( - JsonMapper.fromJson(msgArray.get(1)), - ) } } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/ReqCmd.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/ReqCmd.kt new file mode 100644 index 0000000000..eaf972de6b --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/ReqCmd.kt @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.relay.commands.toRelay + +import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter + +class ReqCmd( + val subId: String, + val filters: List, +) : Command { + override fun label(): String = LABEL + + companion object { + const val LABEL = "REQ" + } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/Filter.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/Filter.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/Filter.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/Filter.kt index d62ddfacef..a34cd01fb5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/Filter.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/Filter.kt @@ -20,9 +20,11 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.filters -import android.util.Log +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper +import com.vitorpamplona.quartz.nip01Core.core.OptimizedSerializable +import com.vitorpamplona.quartz.utils.Log /** * A filter for Nostr events used in relay subscriptions. Supports various criteria @@ -50,8 +52,8 @@ class Filter( val until: Long? = null, val limit: Int? = null, val search: String? = null, -) { - fun toJson() = FilterSerializer.toJson(ids, authors, kinds, tags, since, until, limit, search) +) : OptimizedSerializable { + fun toJson() = OptimizedJsonMapper.toJson(this) fun match(event: Event) = FilterMatcher.match(event, ids, authors, kinds, tags, since, until) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterMatcher.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterMatcher.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterMatcher.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterMatcher.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/normalizer/NormalizedRelayUrl.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/normalizer/NormalizedRelayUrl.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/normalizer/NormalizedRelayUrl.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/normalizer/NormalizedRelayUrl.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/normalizer/RelayUrlNormalizer.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/normalizer/RelayUrlNormalizer.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/normalizer/RelayUrlNormalizer.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/normalizer/RelayUrlNormalizer.kt index c417c8f816..c3c4ca9e79 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/normalizer/RelayUrlNormalizer.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/normalizer/RelayUrlNormalizer.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.normalizer -import android.util.Log import androidx.collection.LruCache +import com.vitorpamplona.quartz.utils.Log +import com.vitorpamplona.quartz.utils.Rfc3986 import kotlinx.coroutines.CancellationException -import org.czeal.rfc3986.URIReference import kotlin.contracts.ExperimentalContracts sealed interface NormalizationResult { @@ -82,14 +82,7 @@ class RelayUrlNormalizer { return false } - private fun norm(url: String) = - NormalizedRelayUrl( - URIReference - .parse(url) - .normalize() - .toString() - .intern(), - ) + private fun norm(url: String) = NormalizedRelayUrl(Rfc3986.normalize(url)) @OptIn(ExperimentalContracts::class) fun fix(url: String): String? { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebSocket.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebSocket.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebSocket.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebSocket.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebSocketListener.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebSocketListener.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebSocketListener.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebSocketListener.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebsocketBuilder.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebsocketBuilder.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebsocketBuilder.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebsocketBuilder.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebsocketBuilderFactory.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebsocketBuilderFactory.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebsocketBuilderFactory.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/WebsocketBuilderFactory.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplate.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplate.kt similarity index 85% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplate.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplate.kt index 3d801e9637..e3db2dd1d4 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplate.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplate.kt @@ -20,26 +20,25 @@ */ package com.vitorpamplona.quartz.nip01Core.signers -import com.fasterxml.jackson.annotation.JsonProperty import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper +import com.vitorpamplona.quartz.nip01Core.core.OptimizedSerializable import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.core.builder import com.vitorpamplona.quartz.nip01Core.core.tagArray -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper import com.vitorpamplona.quartz.utils.TimeUtils class EventTemplate( - @field:JsonProperty("created_at") val createdAt: Long, val kind: Int, val tags: TagArray, val content: String, -) { - fun toJson(): String = JsonMapper.mapper.writeValueAsString(this) +) : OptimizedSerializable { + fun toJson(): String = OptimizedJsonMapper.toJson(this) companion object { - fun fromJson(json: String): EventTemplate = EventTemplateManualDeserializer.fromJson(JsonMapper.mapper.readTree(json)) + fun fromJson(json: String): EventTemplate = OptimizedJsonMapper.fromJsonTo>(json) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSigner.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSigner.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSigner.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSigner.kt index 40dbd3a165..add89ddb7f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSigner.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSigner.kt @@ -64,6 +64,8 @@ abstract class NostrSigner( abstract suspend fun deriveKey(nonce: HexKey): HexKey + abstract fun hasForegroundSupport(): Boolean + suspend fun decrypt( encryptedContent: String, fromPublicKey: HexKey, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSignerInternal.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSignerInternal.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSignerInternal.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSignerInternal.kt index a9fc14f093..2c4ddc5083 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSignerInternal.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSignerInternal.kt @@ -86,6 +86,9 @@ class NostrSignerInternal( signerSync.nip44Decrypt(ciphertext, fromPublicKey) } + // always ready + override fun hasForegroundSupport() = true + override suspend fun decryptZapEvent(event: LnZapRequestEvent): LnZapPrivateEvent { if (!event.isPrivateZap()) throw SignerExceptions.NothingToDecrypt() diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSignerSync.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSignerSync.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSignerSync.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/NostrSignerSync.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/SignerExceptions.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/SignerExceptions.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/SignerExceptions.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/SignerExceptions.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/caches/CacheResults.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/caches/CacheResults.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/caches/CacheResults.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/caches/CacheResults.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/caches/DecryptCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/caches/DecryptCache.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/caches/DecryptCache.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/caches/DecryptCache.kt index 05fc16b4cf..d15827cb7c 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/caches/DecryptCache.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/caches/DecryptCache.kt @@ -20,10 +20,9 @@ */ package com.vitorpamplona.quartz.nip01Core.signers.caches -import android.util.Log import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions -import com.vitorpamplona.quartz.nip55AndroidSigner.client.NostrSignerExternal +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils abstract class DecryptCache( @@ -79,10 +78,6 @@ abstract class DecryptCache( // App received a notifications, asked the signer to decrypt but the permission was not automatic. // It needs the interface but does not have it. It needs to wait for an activity. cache = CacheResults.NeedsForegroundActivityToTryAgain(TimeUtils.tenSecondsFromNow()) - } catch (e: com.fasterxml.jackson.core.JsonParseException) { - Log.w("DecryptCache", "JsonParseException", e) - // Decryption failed. This key might not be able to decrypt anything. Don't try again. - cache = dontTryAgain } catch (e: IllegalStateException) { Log.w("DecryptCache", "IllegalStateException", e) cache = dontTryAgain @@ -115,7 +110,7 @@ abstract class DecryptCache( } } is CacheResults.NeedsForegroundActivityToTryAgain<*> -> { - if (TimeUtils.now() > cachedResult.after && (signer !is NostrSignerExternal || signer.hasForegroundActivity())) { + if (TimeUtils.now() > cachedResult.after && signer.hasForegroundSupport()) { performDecrypt(input) } else { null diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/ATag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/ATag.kt similarity index 87% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/ATag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/ATag.kt index f4ad7a2435..54925b539f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/ATag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/ATag.kt @@ -18,14 +18,19 @@ * 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.quartz.nip01Core.tags.addressables +package com.vitorpamplona.quartz.nip01Core.tags.aTag import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address +import com.vitorpamplona.quartz.nip01Core.core.AddressSerializer +import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.has +import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.ensure @@ -47,14 +52,13 @@ data class ATag( dTag.bytesUsedInMemory() + (relay?.url?.bytesUsedInMemory() ?: 0) - fun toTag() = Address.assemble(kind, pubKeyHex, dTag) + fun toTag() = AddressSerializer.assemble(kind, pubKeyHex, dTag) fun toATagArray() = assemble(toTag(), relay) companion object { const val TAG_NAME = "a" - @JvmStatic fun isTagged(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() fun isSameAddress( @@ -68,47 +72,40 @@ data class ATag( return true } - @JvmStatic fun isTagged( tag: Array, addressId: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == addressId - @JvmStatic fun isTagged( tag: Array, address: ATag, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == address.toTag() - @JvmStatic fun isIn( tag: Array, addressIds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in addressIds - @JvmStatic fun isTaggedWithKind( tag: Array, kind: String, - ) = tag.has(1) && tag[0] == TAG_NAME && Address.isOfKind(tag[1], kind) + ) = tag.has(1) && tag[0] == TAG_NAME && AddressSerializer.isOfKind(tag[1], kind) - @JvmStatic fun parseIfOfKind( tag: Array, kind: String, ) = if (isTaggedWithKind(tag, kind)) parse(tag[1], tag.getOrNull(2)) else null - @JvmStatic fun parseIfIsIn( tag: Array, addresses: Set, ) = if (isIn(tag, addresses)) parse(tag[1], tag.getOrNull(2)) else null - @JvmStatic fun parse( aTagId: String, relay: String?, - ) = Address.parse(aTagId)?.let { + ) = AddressSerializer.parse(aTagId)?.let { ATag( it.kind, it.pubKeyHex, @@ -117,7 +114,6 @@ data class ATag( ) } - @JvmStatic fun parse(tag: Array): ATag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -125,23 +121,20 @@ data class ATag( return parse(tag[1], tag.getOrNull(2)) } - @JvmStatic fun parseValidAddress(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } ensure(tag[1].isNotEmpty()) { return null } - return Address.parse(tag[1])?.toValue() + return AddressSerializer.parse(tag[1])?.toValue() } - @JvmStatic fun parseAddress(tag: Array): Address? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } ensure(tag[1].isNotEmpty()) { return null } - return Address.parse(tag[1]) + return AddressSerializer.parse(tag[1]) } - @JvmStatic fun parseAddressId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -149,7 +142,6 @@ data class ATag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): AddressHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -163,24 +155,23 @@ data class ATag( return AddressHint(tag[1], relayHint) } - @JvmStatic fun assemble( aTagId: HexKey, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, aTagId, relay?.url) - @JvmStatic fun assemble( address: Address, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, address.toValue(), relay?.url) - @JvmStatic fun assemble( kind: Int, pubKey: String, dTag: String, relay: NormalizedRelayUrl?, - ) = assemble(Address.assemble(kind, pubKey, dTag), relay) + ) = assemble(AddressSerializer.assemble(kind, pubKey, dTag), relay) } } + +fun EventHintBundle.toATag() = ATag(event.kind, event.pubKey, event.dTag(), relay) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/EventExt.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/EventExt.kt index ee1c611fac..48259f815b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/EventExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/EventExt.kt @@ -18,7 +18,7 @@ * 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.quartz.nip01Core.tags.addressables +package com.vitorpamplona.quartz.nip01Core.tags.aTag import com.vitorpamplona.quartz.nip01Core.core.Event diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/TagArrayBuilderExt.kt similarity index 83% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/TagArrayBuilderExt.kt index 3b494e0e93..d4782c1944 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/TagArrayBuilderExt.kt @@ -18,18 +18,13 @@ * 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.quartz.nip01Core.tags.addressables +package com.vitorpamplona.quartz.nip01Core.tags.aTag import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder -import com.vitorpamplona.quartz.nip18Reposts.quotes.toQTagArray fun TagArrayBuilder.aTag(tag: ATag) = add(tag.toATagArray()) fun TagArrayBuilder.aTags(tag: List) = addAll(tag.map { it.toATagArray() }) fun TagArrayBuilder.removeATag(tag: ATag) = this.removeIf(ATag::isSameAddress, tag.toATagArray()) - -fun TagArrayBuilder.qTag(tag: ATag) = add(tag.toQTagArray()) - -fun TagArrayBuilder.qTags(tag: List) = addAll(tag.map { it.toQTagArray() }) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/TagArrayExt.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/TagArrayExt.kt index bf36f24541..8ca4b001b1 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/addressables/TagArrayExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/aTag/TagArrayExt.kt @@ -18,7 +18,7 @@ * 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.quartz.nip01Core.tags.addressables +package com.vitorpamplona.quartz.nip01Core.tags.aTag import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.any diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags/DTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag/DTag.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags/DTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag/DTag.kt index b92452f380..2b4b3c16e4 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags/DTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag/DTag.kt @@ -18,7 +18,7 @@ * 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.quartz.nip01Core.tags.dTags +package com.vitorpamplona.quartz.nip01Core.tags.dTag import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.pointerSizeInBytes @@ -33,13 +33,11 @@ class DTag( companion object { const val TAG_NAME = "d" - @JvmStatic fun parse(tags: Array): DTag { require(tags[0] == TAG_NAME) return DTag(tags[1]) } - @JvmStatic fun assemble(dId: String) = arrayOf(TAG_NAME, dId) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag/EventExt.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag/EventExt.kt index a4a0b32747..d24d94eb8e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags/EventExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag/EventExt.kt @@ -18,7 +18,7 @@ * 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.quartz.nip01Core.tags.dTags +package com.vitorpamplona.quartz.nip01Core.tags.dTag import com.vitorpamplona.quartz.nip01Core.core.Event diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag/TagArrayBuilderExt.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag/TagArrayBuilderExt.kt index 1cd4cb49f9..787955a6d4 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag/TagArrayBuilderExt.kt @@ -18,7 +18,7 @@ * 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.quartz.nip01Core.tags.dTags +package com.vitorpamplona.quartz.nip01Core.tags.dTag import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag/TagArrayExt.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag/TagArrayExt.kt index 8e8bb9781d..8d14fcd6a3 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTags/TagArrayExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/dTag/TagArrayExt.kt @@ -18,7 +18,7 @@ * 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.quartz.nip01Core.tags.dTags +package com.vitorpamplona.quartz.nip01Core.tags.dTag import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.firstTagValue diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/ETag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/ETag.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/ETag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/ETag.kt index fe4672f1f0..3e35539c6b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/ETag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/ETag.kt @@ -21,8 +21,10 @@ package com.vitorpamplona.quartz.nip01Core.tags.events import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.has +import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer @@ -57,16 +59,13 @@ data class ETag( companion object { const val TAG_NAME = "e" - @JvmStatic fun isTagged(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].length == 64 - @JvmStatic fun isTagged( tag: Array, eventId: HexKey, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == eventId - @JvmStatic fun parse(tag: Array): ETag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -75,7 +74,6 @@ data class ETag( return ETag(tag[1], pickRelayHint(tag), pickAuthor(tag)) } - @JvmStatic fun parseId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -93,7 +91,6 @@ data class ETag( // pubkey marker ["e", "id", "pubkey"] // incorrect // current root ["e", "id", "marker"] // incorrect - @JvmStatic private fun pickRelayHint(tag: Array): NormalizedRelayUrl? { if (tag.has(2) && tag[2].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[2])) return RelayUrlNormalizer.normalizeOrNull(tag[2]) if (tag.has(3) && tag[3].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[3])) return RelayUrlNormalizer.normalizeOrNull(tag[3]) @@ -101,7 +98,6 @@ data class ETag( return null } - @JvmStatic private fun pickAuthor(tag: Array): HexKey? { if (tag.has(2) && tag[2].length == 64) return tag[2] if (tag.has(3) && tag[3].length == 64) return tag[3] @@ -109,7 +105,6 @@ data class ETag( return null } - @JvmStatic fun parseAsHint(tag: Array): EventIdHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -123,7 +118,6 @@ data class ETag( return EventIdHint(tag[1], hint) } - @JvmStatic fun assemble( eventId: HexKey, relay: NormalizedRelayUrl?, @@ -131,3 +125,7 @@ data class ETag( ) = arrayOfNotNull(TAG_NAME, eventId, relay?.url, author) } } + +fun EventHintBundle.toETag() = ETag(event.id, relay, event.pubKey) + +fun EventHintBundle.toETagArray() = ETag.assemble(event.id, relay, event.pubKey) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/EventReference.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/EventReference.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/EventReference.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/EventReference.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/GenericETag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/GenericETag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/GenericETag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/GenericETag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayBuilderExt.kt similarity index 86% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayBuilderExt.kt index d45141c0e8..cbb95215cc 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayBuilderExt.kt @@ -22,12 +22,7 @@ package com.vitorpamplona.quartz.nip01Core.tags.events import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder -import com.vitorpamplona.quartz.nip18Reposts.quotes.toQTagArray fun TagArrayBuilder.eTag(tag: ETag) = add(tag.toTagArray()) fun TagArrayBuilder.eTags(tag: List) = addAll(tag.map { it.toTagArray() }) - -fun TagArrayBuilder.qTag(tag: ETag) = add(tag.toQTagArray()) - -fun TagArrayBuilder.qTags(tag: List) = addAll(tag.map { it.toQTagArray() }) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/events/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeoHashTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeoHashTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeoHashTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeoHashTag.kt index 5518184dab..708b788c7e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeoHashTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeoHashTag.kt @@ -28,20 +28,16 @@ class GeoHashTag { companion object { const val TAG_NAME = "g" - @JvmStatic fun isTagged(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun parse(tags: Array): String? { ensure(tags.has(1)) { return null } ensure(tags[0] == TAG_NAME) { return null } return tags[1] } - @JvmStatic fun assembleSingle(geohash: String) = arrayOf(TAG_NAME, geohash) - @JvmStatic fun geoMipMap(geohash: String): List = geohash.indices.map { geohash.substring(0, it + 1) }.reversed() fun geohashMipMap(geohash: String): TagArray = geoMipMap(geohash).map { assembleSingle(it) }.toTypedArray() diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeohashPrecision.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeohashPrecision.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeohashPrecision.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/GeohashPrecision.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/HashtagTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/HashtagTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/HashtagTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/HashtagTag.kt index 581e65a05c..bbb985dbde 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/HashtagTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/HashtagTag.kt @@ -27,7 +27,6 @@ class HashtagTag { companion object { const val TAG_NAME = "t" - @JvmStatic fun isTagged(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() fun isTagged( @@ -40,7 +39,6 @@ class HashtagTag { hashtags: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in hashtags - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/MipMapHashTags.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/MipMapHashTags.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/MipMapHashTags.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/MipMapHashTags.kt index c11dac244e..4e14f78bfd 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/MipMapHashTags.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/MipMapHashTags.kt @@ -20,15 +20,13 @@ */ package com.vitorpamplona.quartz.nip01Core.tags.hashtags -import java.util.Locale - fun hashtagAlts(tag: String): Set = setOf( tag, tag.lowercase(), tag.uppercase(), tag.replaceFirstChar { - if (it.isLowerCase()) it.titlecase(Locale.ROOT) else it.toString() + if (it.isLowerCase()) it.titlecase() else it.toString() }, ) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/hashtags/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/KindTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/KindTag.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/KindTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/KindTag.kt index a3b9ad43fc..62569ff8da 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/KindTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/KindTag.kt @@ -40,7 +40,6 @@ class KindTag { kinds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in kinds - @JvmStatic fun parse(tag: Array): Int? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/kinds/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/EntityExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/EntityExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/EntityExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/EntityExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/PTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/PTag.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/PTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/PTag.kt index 92e0f48ed5..c827ff84d0 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/PTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/PTag.kt @@ -21,10 +21,12 @@ package com.vitorpamplona.quartz.nip01Core.tags.people import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.Tag import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray +import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer @@ -59,7 +61,6 @@ data class PTag( key: HexKey, ): Boolean = tag.has(1) && tag[0] == TAG_NAME && tag[1] == key - @JvmStatic fun parse(tag: Tag): PTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -75,7 +76,6 @@ data class PTag( return null } - @JvmStatic fun parseKey(tag: Array): HexKey? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -83,7 +83,6 @@ data class PTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): PubKeyHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -97,10 +96,11 @@ data class PTag( return PubKeyHint(tag[1], hint) } - @JvmStatic fun assemble( pubkey: HexKey, relayHint: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, pubkey, relayHint?.url) } } + +fun EventHintBundle.toPTag() = PTag(event.pubKey, authorHomeRelay) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/PubKeyReferenceTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/PubKeyReferenceTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/PubKeyReferenceTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/PubKeyReferenceTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/people/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/publishedAt/PublishedAtProvider.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/publishedAt/PublishedAtProvider.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/publishedAt/PublishedAtProvider.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/publishedAt/PublishedAtProvider.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/HttpUrlFormatter.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/HttpUrlFormatter.kt similarity index 88% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/HttpUrlFormatter.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/HttpUrlFormatter.kt index 5854fa927a..40d1ebd7b0 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/HttpUrlFormatter.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/HttpUrlFormatter.kt @@ -18,9 +18,9 @@ * 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.quartz.nip96FileStorage +package com.vitorpamplona.quartz.nip01Core.tags.references -import org.czeal.rfc3986.URIReference +import com.vitorpamplona.quartz.utils.Rfc3986 class HttpUrlFormatter { companion object { @@ -55,15 +55,12 @@ class HttpUrlFormatter { val newUrl = addSchemeIfNeeded(url) return try { - URIReference.parse(newUrl).normalize().toString() + Rfc3986.normalize(newUrl) } catch (e: Exception) { newUrl } } - fun isValidUrl(url: String): Boolean = - runCatching { - URIReference.parse(addSchemeIfNeeded(url)) - }.isSuccess + fun isValidUrl(url: String): Boolean = Rfc3986.isValidUrl(addSchemeIfNeeded(url)) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/ReferenceTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/ReferenceTag.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/ReferenceTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/ReferenceTag.kt index aeba87840b..aedad53a39 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/ReferenceTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/ReferenceTag.kt @@ -21,33 +21,28 @@ package com.vitorpamplona.quartz.nip01Core.tags.references import com.vitorpamplona.quartz.nip01Core.core.has -import com.vitorpamplona.quartz.nip96FileStorage.HttpUrlFormatter import com.vitorpamplona.quartz.utils.ensure class ReferenceTag { companion object { const val TAG_NAME = "r" - @JvmStatic fun isTagged( tag: Array, reference: String, ): Boolean = tag.has(1) && tag[0] == TAG_NAME && tag[1] == reference - @JvmStatic fun isIn( tag: Array, references: Set, ): Boolean = tag.has(1) && tag[0] == TAG_NAME && tag[1] in references - @JvmStatic fun hasReference(tag: Array): Boolean { ensure(tag.has(1)) { return false } ensure(tag[0] == TAG_NAME) { return false } return tag[1].isNotEmpty() } - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -55,10 +50,8 @@ class ReferenceTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, HttpUrlFormatter.normalize(url)) - @JvmStatic fun assemble(urls: List): List> = urls.mapTo(HashSet()) { HttpUrlFormatter.normalize(it) }.map { arrayOf(TAG_NAME, it) } } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/tags/references/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/ContactListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/ContactListEvent.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/ContactListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/ContactListEvent.kt index edf55518c8..a3f6dde135 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/ContactListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/ContactListEvent.kt @@ -29,7 +29,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser import com.vitorpamplona.quartz.nip02FollowList.tags.ContactTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/RelaySet.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/RelaySet.kt similarity index 86% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/RelaySet.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/RelaySet.kt index 5910c392c9..139957998a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/RelaySet.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/RelaySet.kt @@ -20,10 +20,11 @@ */ package com.vitorpamplona.quartz.nip02FollowList -import android.util.Log -import com.fasterxml.jackson.module.kotlin.readValue -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.core.JsonMapper +import com.vitorpamplona.quartz.utils.Log +import kotlinx.serialization.Serializable +@Serializable data class ReadWrite( val read: Boolean, val write: Boolean, @@ -31,12 +32,12 @@ data class ReadWrite( class RelaySet { companion object { - fun assemble(relayUse: Map): String = JsonMapper.mapper.writeValueAsString(relayUse) + fun assemble(relayUse: Map): String = JsonMapper.toJson(relayUse) fun parse(content: String): Map? = try { if (content.isNotEmpty()) { - JsonMapper.mapper.readValue>(content) + JsonMapper.fromJson>(content) } else { null } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/tags/ContactTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/tags/ContactTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/tags/ContactTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/tags/ContactTag.kt index 548b020a38..ace9606d3a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/tags/ContactTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip02FollowList/tags/ContactTag.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.quartz.nip02FollowList.tags -import android.util.Log import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.has @@ -29,6 +28,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip19Bech32.decodePublicKey +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.ensure @@ -61,10 +61,8 @@ data class ContactTag( companion object { const val TAG_NAME = "p" - @JvmStatic fun isTagged(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun parse(tag: Array): ContactTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -75,7 +73,6 @@ data class ContactTag( return ContactTag(tag[1], hint, tag.getOrNull(3)) } - @JvmStatic fun parseValid(tag: Array): ContactTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -91,7 +88,6 @@ data class ContactTag( } } - @JvmStatic fun parseKey(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -99,7 +95,6 @@ data class ContactTag( return tag[1] } - @JvmStatic fun parseValidKey(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -112,7 +107,6 @@ data class ContactTag( } } - @JvmStatic fun parseAsHint(tag: Array): PubKeyHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -125,7 +119,6 @@ data class ContactTag( return PubKeyHint(tag[1], hint) } - @JvmStatic fun assemble( pubkey: HexKey, relayUri: NormalizedRelayUrl? = null, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsEvent.kt similarity index 87% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsEvent.kt index 5d3980940e..37b80846fe 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsEvent.kt @@ -28,10 +28,11 @@ import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate +import com.vitorpamplona.quartz.nip01Core.tags.events.toETag import com.vitorpamplona.quartz.nip03Timestamp.tags.TargetEventTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.utils.TimeUtils -import java.util.Base64 +import kotlin.io.encoding.Base64 @Immutable class OtsEvent( @@ -53,9 +54,9 @@ class OtsEvent( fun otsByteArray(): ByteArray = decodeOtsState(content) - fun verifyState(resolver: OtsResolver): VerificationState = digestEventId()?.let { verify(otsByteArray(), it, resolver) } ?: VerificationState.Error("Digest Not found") + suspend fun verifyState(resolver: OtsResolver): VerificationState = digestEventId()?.let { verify(otsByteArray(), it, resolver) } ?: VerificationState.Error("Digest Not found") - fun verify(resolver: OtsResolver): Long? = (verifyState(resolver) as? VerificationState.Verified)?.verifiedTime + suspend fun verify(resolver: OtsResolver): Long? = (verifyState(resolver) as? VerificationState.Verified)?.verifiedTime companion object { const val KIND = 1040 @@ -65,7 +66,7 @@ class OtsEvent( * Stamp is used to save OTS requests locally while we want for the bitcoin * blockchain to include the block with the proof. */ - fun stamp( + suspend fun stamp( eventId: HexKey, resolver: OtsResolver, ) = resolver.stamp(eventId.hexToByteArray()) @@ -75,7 +76,7 @@ class OtsEvent( * the block with it. If the return is not null, the attestation can be sent * to Nostr. */ - fun upgrade( + suspend fun upgrade( otsState: ByteArray, eventId: HexKey, resolver: OtsResolver, @@ -85,15 +86,15 @@ class OtsEvent( * Verifies if the attestation contained in a Nostr Event is valid by checking * with the blockchain. */ - fun verify( + suspend fun verify( otsState: ByteArray, eventId: HexKey, resolver: OtsResolver, ) = resolver.verify(otsState, eventId.hexToByteArray()) - fun encodeOtsState(otsState: ByteArray) = Base64.getEncoder().encodeToString(otsState) + fun encodeOtsState(otsState: ByteArray) = Base64.encode(otsState) - fun decodeOtsState(content: String) = Base64.getDecoder().decode(content) + fun decodeOtsState(content: String) = Base64.decode(content) fun build( eventId: HexKey, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsResolver.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsResolver.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsResolver.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsResolver.kt index 8dcb28aca6..4192419fd5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsResolver.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsResolver.kt @@ -20,17 +20,15 @@ */ package com.vitorpamplona.quartz.nip03Timestamp -import android.util.Log import com.vitorpamplona.quartz.nip03Timestamp.ots.BitcoinExplorer -import com.vitorpamplona.quartz.nip03Timestamp.ots.CalendarBuilder import com.vitorpamplona.quartz.nip03Timestamp.ots.DetachedTimestampFile import com.vitorpamplona.quartz.nip03Timestamp.ots.Hash import com.vitorpamplona.quartz.nip03Timestamp.ots.OpenTimestamps +import com.vitorpamplona.quartz.nip03Timestamp.ots.RemoteCalendar import com.vitorpamplona.quartz.nip03Timestamp.ots.VerifyResult import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.UrlException -import com.vitorpamplona.quartz.nip03Timestamp.ots.http.BlockstreamExplorer -import com.vitorpamplona.quartz.nip03Timestamp.ots.http.CalendarPureJavaBuilder import com.vitorpamplona.quartz.nip03Timestamp.ots.op.OpSHA256 +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException /** @@ -43,10 +41,10 @@ import kotlinx.coroutines.CancellationException * @property calendarBuilder The calendar builder used for stamping operations. */ class OtsResolver( - explorer: BitcoinExplorer = BlockstreamExplorer(), - calendarBuilder: CalendarBuilder = CalendarPureJavaBuilder(), + explorer: BitcoinExplorer, + calendar: RemoteCalendar, ) { - val ots: OpenTimestamps = OpenTimestamps(explorer, calendarBuilder) + val ots: OpenTimestamps = OpenTimestamps(explorer, calendar) /** * Returns a human-readable information string about the given OTS file. @@ -62,7 +60,7 @@ class OtsResolver( * @param data The data to be timestamped. * @return A serialized DetachedTimestampFile containing the timestamp proof. */ - fun stamp(data: ByteArray): ByteArray { + suspend fun stamp(data: ByteArray): ByteArray { val hash = Hash(data, OpSHA256.TAG) val file = DetachedTimestampFile.from(hash) val timestamp = ots.stamp(file) @@ -77,7 +75,7 @@ class OtsResolver( * @param data The original data that was timestamped. * @return A serialized DetachedTimestampFile with upgraded proof if successful, null otherwise. */ - fun upgrade( + suspend fun upgrade( otsState: ByteArray, data: ByteArray, ): ByteArray? { @@ -102,7 +100,7 @@ class OtsResolver( * @param data The original data to verify against. * @return VerificationState indicating the result of the verification. */ - fun verify( + suspend fun verify( otsFile: ByteArray, data: ByteArray, ): VerificationState = verify(DetachedTimestampFile.deserialize(otsFile), data) @@ -114,7 +112,7 @@ class OtsResolver( * @param data The original data to verify against. * @return VerificationState indicating the result of the verification. */ - fun verify( + suspend fun verify( detachedOts: DetachedTimestampFile, data: ByteArray, ): VerificationState { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsResolverBuilder.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsResolverBuilder.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsResolverBuilder.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsResolverBuilder.kt index 502e1e78cf..51c7f616d9 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsResolverBuilder.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/OtsResolverBuilder.kt @@ -23,7 +23,3 @@ package com.vitorpamplona.quartz.nip03Timestamp interface OtsResolverBuilder { fun build(): OtsResolver } - -class DefaultOtsResolverBuilder : OtsResolverBuilder { - override fun build(): OtsResolver = OtsResolver() -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/VerificationState.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/VerificationState.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/VerificationState.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/VerificationState.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/VerificationStateCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/VerificationStateCache.kt similarity index 88% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/VerificationStateCache.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/VerificationStateCache.kt index 09b5b91e51..f259e09e50 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/VerificationStateCache.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/VerificationStateCache.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.quartz.nip03Timestamp -import android.util.LruCache +import androidx.collection.LruCache import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.utils.TimeUtils @@ -29,21 +29,23 @@ class VerificationStateCache( ) { private val cache = LruCache(200) - fun verify(event: OtsEvent): VerificationState { + suspend fun verify(event: OtsEvent): VerificationState { cache.put(event.id, VerificationState.Verifying) return event.verifyState(otsResolverBuilder.build()).also { cache.put(event.id, it) } } - fun cacheVerify(event: OtsEvent): VerificationState = + fun justCache(event: OtsEvent): VerificationState? = cache[event.id] + + suspend fun cacheVerify(event: OtsEvent): VerificationState = when (val verif = cache[event.id]) { is VerificationState.Verifying -> verif is VerificationState.Verified -> verif is VerificationState.NetworkError -> { // try again in 5 mins if (verif.time < TimeUtils.fiveMinutesAgo()) { - event.verifyState(otsResolverBuilder.build()).also { cache.put(event.id, it) } - } else { verify(event) + } else { + verif } } is VerificationState.Error -> verif diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/BitcoinExplorer.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/BitcoinExplorer.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/BitcoinExplorer.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/BitcoinExplorer.kt index a3c094c6f6..7c6914c08d 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/BitcoinExplorer.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/BitcoinExplorer.kt @@ -28,8 +28,7 @@ interface BitcoinExplorer { * @return the blockheader of the hash * @throws Exception desc */ - @Throws(Exception::class) - fun block(hash: String): BlockHeader + suspend fun block(hash: String): BlockHeader /** * Retrieve the block hash from the block height. @@ -38,6 +37,5 @@ interface BitcoinExplorer { * @return the hash of the block at height height * @throws Exception desc */ - @Throws(Exception::class) - fun blockHash(height: Int): String + suspend fun blockHash(height: Int): String } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/BlockHeader.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/BlockHeader.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/BlockHeader.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/BlockHeader.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/DetachedTimestampFile.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/DetachedTimestampFile.kt similarity index 75% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/DetachedTimestampFile.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/DetachedTimestampFile.kt index 52699b94e9..758066f327 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/DetachedTimestampFile.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/DetachedTimestampFile.kt @@ -23,11 +23,6 @@ package com.vitorpamplona.quartz.nip03Timestamp.ots import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.DeserializationException import com.vitorpamplona.quartz.nip03Timestamp.ots.op.Op import com.vitorpamplona.quartz.nip03Timestamp.ots.op.OpCrypto -import com.vitorpamplona.quartz.nip03Timestamp.ots.op.OpSHA256 -import java.io.File -import java.io.IOException -import java.io.InputStream -import java.security.NoSuchAlgorithmException /** * Class representing Detached com.vitorpamplona.quartz.ots.Timestamp File. @@ -176,7 +171,6 @@ class DetachedTimestampFile( * @return The generated com.vitorpamplona.quartz.ots.DetachedTimestampFile object. * @throws NoSuchAlgorithmException desc */ - @Throws(NoSuchAlgorithmException::class) fun from( fileHashOp: OpCrypto, ctx: StreamDeserializationContext, @@ -204,44 +198,6 @@ class DetachedTimestampFile( return DetachedTimestampFile(fileHashOp, Timestamp(fdHash)) } - /** - * Read the Detached com.vitorpamplona.quartz.ots.Timestamp File from hash. - * - * @param inputStream The InputStream of the file to hash - * @return The generated com.vitorpamplona.quartz.ots.DetachedTimestampFile object. - * @throws Exception if the input stream is null - */ - @Throws(Exception::class) - fun from(inputStream: InputStream): DetachedTimestampFile { - try { - val fileTimestamp: DetachedTimestampFile = - from(OpSHA256(), inputStream) // Read from file reader stream - return fileTimestamp - } catch (e: NoSuchAlgorithmException) { - e.printStackTrace() - throw Exception() - } - } - - /** - * Read the Detached com.vitorpamplona.quartz.ots.Timestamp File from InputStream. - * - * @param fileHashOp The file hash operation. - * @param inputStream The input stream file. - * @return The generated com.vitorpamplona.quartz.ots.DetachedTimestampFile object. - * @throws IOException desc - * @throws NoSuchAlgorithmException desc - */ - @Throws(IOException::class, NoSuchAlgorithmException::class) - fun from( - fileHashOp: OpCrypto, - inputStream: InputStream, - ): DetachedTimestampFile { - val fdHash = fileHashOp.hashFd(inputStream) - - return DetachedTimestampFile(fileHashOp, Timestamp(fdHash)) - } - /** * Read the Detached com.vitorpamplona.quartz.ots.Timestamp File from hash. * @@ -249,24 +205,5 @@ class DetachedTimestampFile( * @return The generated com.vitorpamplona.quartz.ots.DetachedTimestampFile object. */ fun from(hash: Hash): DetachedTimestampFile = DetachedTimestampFile(hash.op, Timestamp(hash.value)) - - /** - * Read the Detached com.vitorpamplona.quartz.ots.Timestamp File from File. - * - * @param fileHashOp The file hash operation. - * @param file The hash file. - * @return The generated com.vitorpamplona.quartz.ots.DetachedTimestampFile object. - * @throws IOException desc - * @throws NoSuchAlgorithmException desc - */ - @Throws(IOException::class, NoSuchAlgorithmException::class) - fun from( - fileHashOp: OpCrypto, - file: File?, - ): DetachedTimestampFile { - val fdHash = fileHashOp.hashFd(file) - - return DetachedTimestampFile(fileHashOp, Timestamp(fdHash)) - } } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Hash.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Hash.kt similarity index 74% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Hash.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Hash.kt index 0dccda379a..9faa76a3ca 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Hash.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Hash.kt @@ -26,10 +26,6 @@ import com.vitorpamplona.quartz.nip03Timestamp.ots.op.OpRIPEMD160 import com.vitorpamplona.quartz.nip03Timestamp.ots.op.OpSHA1 import com.vitorpamplona.quartz.nip03Timestamp.ots.op.OpSHA256 import com.vitorpamplona.quartz.utils.Hex.encode -import java.io.File -import java.io.IOException -import java.io.InputStream -import java.security.NoSuchAlgorithmException /** * Create a Hash object. @@ -116,7 +112,6 @@ class Hash( * @throws IOException desc * @throws NoSuchAlgorithmException desc */ - @Throws(IOException::class, NoSuchAlgorithmException::class) fun from( bytes: ByteArray, algorithm: Byte, @@ -126,45 +121,5 @@ class Hash( return Hash(value, algorithm) } - - /** - * Build hash from File. - * - * @param file The File of data to hash. - * @param algorithm The hash file. - * @return The generated com.vitorpamplona.quartz.ots.Hash object. - * @throws IOException desc - * @throws NoSuchAlgorithmException desc - */ - @Throws(IOException::class, NoSuchAlgorithmException::class) - fun from( - file: File?, - algorithm: Byte, - ): Hash { - val opCrypto: OpCrypto = getOp(algorithm) - val value = opCrypto.hashFd(file) - - return Hash(value, algorithm) - } - - /** - * Build hash from InputStream. - * - * @param inputStream The InputStream of data to hash. - * @param algorithm The hash file. - * @return The generated com.vitorpamplona.quartz.ots.Hash object. - * @throws IOException desc - * @throws NoSuchAlgorithmException desc - */ - @Throws(IOException::class, NoSuchAlgorithmException::class) - fun from( - inputStream: InputStream, - algorithm: Byte, - ): Hash { - val opCrypto: OpCrypto = getOp(algorithm) - val value = opCrypto.hashFd(inputStream) - - return Hash(value, algorithm) - } } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Merkle.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Merkle.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Merkle.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Merkle.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OpenTimestamps.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OpenTimestamps.kt similarity index 74% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OpenTimestamps.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OpenTimestamps.kt index c99f5c6fa0..bc20805470 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OpenTimestamps.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OpenTimestamps.kt @@ -20,34 +20,27 @@ */ package com.vitorpamplona.quartz.nip03Timestamp.ots -import android.util.Log import com.vitorpamplona.quartz.nip01Core.core.toHexKey -import com.vitorpamplona.quartz.nip03Timestamp.ots.Utils.arrayReverse -import com.vitorpamplona.quartz.nip03Timestamp.ots.Utils.randBytes import com.vitorpamplona.quartz.nip03Timestamp.ots.VerifyResult.Chains import com.vitorpamplona.quartz.nip03Timestamp.ots.attestation.BitcoinBlockHeaderAttestation import com.vitorpamplona.quartz.nip03Timestamp.ots.attestation.PendingAttestation import com.vitorpamplona.quartz.nip03Timestamp.ots.attestation.TimeAttestation import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.VerificationException -import com.vitorpamplona.quartz.nip03Timestamp.ots.http.Calendar -import com.vitorpamplona.quartz.nip03Timestamp.ots.http.CalendarAsyncSubmit import com.vitorpamplona.quartz.nip03Timestamp.ots.op.OpAppend import com.vitorpamplona.quartz.nip03Timestamp.ots.op.OpCrypto import com.vitorpamplona.quartz.nip03Timestamp.ots.op.OpSHA256 import com.vitorpamplona.quartz.utils.Hex -import java.io.IOException -import java.nio.charset.StandardCharsets -import java.security.NoSuchAlgorithmException -import java.util.Optional -import java.util.concurrent.ArrayBlockingQueue -import java.util.concurrent.Executors +import com.vitorpamplona.quartz.utils.Log +import com.vitorpamplona.quartz.utils.RandomInstance +import com.vitorpamplona.quartz.utils.mapNotNullAsync +import kotlinx.coroutines.CancellationException /** * The main class for timestamp operations. */ class OpenTimestamps( var explorer: BitcoinExplorer, - var calBuilder: CalendarBuilder?, + var calendar: RemoteCalendar, ) { /** * Show information on a detached timestamp with verbose option. @@ -97,20 +90,17 @@ class OpenTimestamps( * * @param fileTimestamp The timestamp to stamp. * @param calendarsUrl The list of calendar urls. - * @param m The number of calendar to use. * @return The plain array buffer of stamped. * @throws IOException if fileTimestamp is not valid, or the stamp procedure fails. */ - @Throws(IOException::class) - fun stamp( + suspend fun stamp( fileTimestamp: DetachedTimestampFile?, calendarsUrl: MutableList = mutableListOf(), - m: Int? = 0, ): Timestamp { val fileTimestamps: MutableList = ArrayList() fileTimestamps.add(fileTimestamp!!) - return stamp(fileTimestamps, calendarsUrl, m) + return stamp(fileTimestamps, calendarsUrl) } /** @@ -118,21 +108,17 @@ class OpenTimestamps( * * @param fileTimestamps The list of timestamp to stamp. * @param calendarsUrl The list of calendar urls. - * @param m The number of calendar to use. * @return The plain array buffer of stamped. - * @throws IOException if fileTimestamp is not valid, or the stamp procedure fails. + * @throws IllegalArgumentException if fileTimestamp is not valid, or the stamp procedure fails. */ - @Throws(IOException::class) - fun stamp( + suspend fun stamp( fileTimestamps: MutableList, calendarsUrl: MutableList, - m: Int?, ): Timestamp { // Parse parameters var calendarsUrl = calendarsUrl - var m = m if (fileTimestamps.isEmpty()) { - throw IOException() + throw IllegalArgumentException() } if (calendarsUrl.isEmpty()) { @@ -142,29 +128,11 @@ class OpenTimestamps( calendarsUrl.add("https://finney.calendar.eternitywall.com") } - if (m == null || m <= 0) { - if (calendarsUrl.size == 0) { - m = 2 - } else if (calendarsUrl.size == 1) { - m = 1 - } else { - m = calendarsUrl.size - } - } - - if (m < 0 || m > calendarsUrl.size) { - Log.e( - "OpenTimestamp", - "m cannot be greater than available calendar neither less or equal 0", - ) - throw IOException() - } - // Build markle tree val merkleTip = makeMerkleTree(fileTimestamps) // Stamping - val resultTimestamp = create(merkleTip, calendarsUrl, m) + val resultTimestamp = create(merkleTip, calendarsUrl) // Result of timestamp serialization if (fileTimestamps.size == 1) { @@ -182,60 +150,20 @@ class OpenTimestamps( * @param m Number of calendars to use. * @return The created timestamp. */ - private fun create( + private suspend fun create( timestamp: Timestamp, calendarUrls: MutableList, - m: Int, ): Timestamp { - val capacity = calendarUrls.size - val executor = Executors.newFixedThreadPool(4) - val queue = ArrayBlockingQueue>(capacity) - - // Submit to all public calendars - for (calendarUrl in calendarUrls) { - Log.i("OpenTimestamps", "Submitting to remote calendar $calendarUrl") - - try { - val task = CalendarAsyncSubmit(calendarUrl, timestamp.digest) - task.setQueue(queue) - executor.submit>(task) - } catch (e: Exception) { - e.printStackTrace() + val responses = + mapNotNullAsync(calendarUrls) { calendarUrl -> + Log.i("OpenTimestamps", "Submitting to remote calendar $calendarUrl") + calendar.submit(calendarUrl, timestamp.digest) } + + responses.forEach { + timestamp.merge(it) } - var count = 0 - - count = 0 - while (count < capacity && count < m) { - try { - val optionalStamp = queue.take() - - if (optionalStamp.isPresent()) { - try { - val time = optionalStamp.get() - timestamp.merge(time) - Log.i("Open", "" + timestamp.attestations.size) - } catch (e: Exception) { - e.printStackTrace() - } - } - } catch (e: Exception) { - e.printStackTrace() - } - count++ - } - - if (count < m) { - Log.e( - "OpenTimestamp", - "Failed to create timestamp: requested " + m.toString() + " attestation" + (if (m > 1) "s" else "") + " but received only " + count.toString(), - ) - } - - // shut down the executor service now - executor.shutdown() - return timestamp } @@ -249,14 +177,7 @@ class OpenTimestamps( val merkleRoots: MutableList = ArrayList() for (fileTimestamp in fileTimestamps) { - var bytesRandom16 = ByteArray(16) - - try { - bytesRandom16 = randBytes(16) - } catch (e: NoSuchAlgorithmException) { - e.printStackTrace() - } - + val bytesRandom16 = RandomInstance.bytes(16) val nonceAppendedStamp = fileTimestamp.timestamp.add(OpAppend(bytesRandom16)) val merkleRoot = nonceAppendedStamp.add(OpSHA256()) merkleRoots.add(merkleRoot) @@ -275,7 +196,7 @@ class OpenTimestamps( * @throws Exception if the verification procedure fails. */ @Throws(Exception::class) - fun verify( + suspend fun verify( ots: DetachedTimestampFile, diggest: ByteArray, ): HashMap { @@ -296,7 +217,7 @@ class OpenTimestamps( * @throws Exception if the verification procedure fails. */ @Throws(Exception::class) - fun verify(timestamp: Timestamp): HashMap { + suspend fun verify(timestamp: Timestamp): HashMap { val verifyResults = HashMap() for (item in timestamp.allAttestations().entries) { @@ -341,7 +262,7 @@ class OpenTimestamps( * @throws Exception if the verification procedure fails. */ @Throws(VerificationException::class, Exception::class) - fun verify( + suspend fun verify( attestation: BitcoinBlockHeaderAttestation, msg: ByteArray, ): Long? { @@ -360,7 +281,7 @@ class OpenTimestamps( throw e2 } - return attestation.verifyAgainstBlockheader(arrayReverse(msg), blockInfo) + return attestation.verifyAgainstBlockheader(msg.reversedArray(), blockInfo) } /** @@ -371,7 +292,7 @@ class OpenTimestamps( * @throws Exception if the upgrading procedure fails. */ @Throws(Exception::class) - fun upgrade(detachedTimestamp: DetachedTimestampFile): Boolean { + suspend fun upgrade(detachedTimestamp: DetachedTimestampFile): Boolean { // Upgrade timestamp val changed = upgrade(detachedTimestamp.timestamp) return changed @@ -386,7 +307,7 @@ class OpenTimestamps( * @throws Exception if the upgrading procedure fails. */ @Throws(Exception::class) - fun upgrade(timestamp: Timestamp): Boolean { + suspend fun upgrade(timestamp: Timestamp): Boolean { // Check remote calendars for upgrades. // This time we only check PendingAttestations - we can't be as agressive. @@ -396,23 +317,24 @@ class OpenTimestamps( for (subStamp in timestamp.directlyVerified()) { for (attestation in subStamp.attestations) { if (attestation is PendingAttestation && !subStamp.isTimestampComplete) { - val calendarUrl = String(attestation.uri, StandardCharsets.UTF_8) + val calendarUrl = attestation.uri.decodeToString() // var calendarUrl = calendarUrls[0]; val commitment = subStamp.digest try { - val calendar = Calendar(calendarUrl) - val upgradedStamp = upgrade(subStamp, calendar, commitment, existingAttestations) + val upgradedStamp = upgrade(subStamp, calendarUrl, commitment, existingAttestations) try { subStamp.merge(upgradedStamp) } catch (e: Exception) { + if (e is CancellationException) throw e e.printStackTrace() } upgraded = true } catch (e: Exception) { - Log.i("OpenTimestamps", e.message ?: "${e.javaClass.simpleName}") + if (e is CancellationException) throw e + Log.w("OpenTimestamps", e.message ?: "", e) } } } @@ -422,24 +344,24 @@ class OpenTimestamps( } @Throws(Exception::class) - private fun upgrade( + private suspend fun upgrade( subStamp: Timestamp, - calendar: Calendar, + calendarUrl: String, commitment: ByteArray, existingAttestations: MutableSet, ): Timestamp { val upgradedStamp: Timestamp = try { - calendar.getTimestamp(commitment) + calendar.getTimestamp(calendarUrl, commitment) } catch (e: Exception) { - Log.i("OpenTimestamps", "Calendar " + calendar.url + ": " + e.message) + Log.i("OpenTimestamps", "Calendar " + calendarUrl + ": " + e.message) throw e } val attsFromRemote: MutableSet = upgradedStamp.getAttestations() if (attsFromRemote.isNotEmpty()) { - Log.i("OpenTimestamps", "Got 1 attestation(s) from " + calendar.url) + Log.i("OpenTimestamps", "Got 1 attestation(s) from $calendarUrl") } // Set difference from remote attestations & existing attestations diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OtsBlockHeightCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OtsBlockHeightCache.kt new file mode 100644 index 0000000000..85eac980fe --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/OtsBlockHeightCache.kt @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2025 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.quartz.nip03Timestamp.ots + +import androidx.collection.LruCache + +class OtsBlockHeightCache { + val cacheHeaders = LruCache(100) + val cacheHeights = LruCache(100) + + fun getHeight(key: Int): String? = cacheHeights.get(key) + + fun getHeader(key: String): BlockHeader? = cacheHeaders.get(key) + + fun putHeight( + key: Int, + value: String, + ) = cacheHeights.put(key, value) + + fun putHeader( + key: String, + value: BlockHeader, + ) = cacheHeaders.put(key, value) +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/README.md b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/README.md similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/README.md rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/README.md diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/RemoteCalendar.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/RemoteCalendar.kt new file mode 100644 index 0000000000..ee282c2afb --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/RemoteCalendar.kt @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2025 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.quartz.nip03Timestamp.ots + +import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.CommitmentNotFoundException +import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.DeserializationException +import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.ExceededSizeException +import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.UrlException + +interface RemoteCalendar { + /** + * Submitting a digest to remote calendar. Returns a com.eternitywall.ots.Timestamp committing to that digest. + * + * @param digest The digest hash to send. + * @return the Timestamp received from the calendar. + * @throws ExceededSizeException if response is too big. + * @throws UrlException if url is not reachable. + * @throws DeserializationException if the data is corrupt + */ + suspend fun submit( + url: String, + digest: ByteArray, + ): Timestamp + + /** + * Get a timestamp for a given commitment. + * + * @param commitment The digest hash to send. + * @return the Timestamp from the calendar server (with blockchain information if already written). + * @throws ExceededSizeException if response is too big. + * @throws UrlException if url is not reachable. + * @throws CommitmentNotFoundException if commit is not found. + * @throws DeserializationException if the data is corrupt + */ + suspend fun getTimestamp( + url: String, + commitment: ByteArray, + ): Timestamp +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/StreamDeserializationContext.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/StreamDeserializationContext.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/StreamDeserializationContext.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/StreamDeserializationContext.kt index 35a56451db..411dc48406 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/StreamDeserializationContext.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/StreamDeserializationContext.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.quartz.nip03Timestamp.ots import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.DeserializationException -import java.util.Arrays class StreamDeserializationContext( var output: ByteArray, @@ -39,7 +38,7 @@ class StreamDeserializationContext( } // const uint8Array = new Uint8Array(this.buffer,this.counter,l); - val uint8Array = Arrays.copyOfRange(this.output, this.counter, this.counter + l) + val uint8Array = this.output.copyOfRange(this.counter, this.counter + l) this.counter += l return uint8Array @@ -80,7 +79,6 @@ class StreamDeserializationContext( return this.read(expectedLength) } - @JvmOverloads @Throws(DeserializationException::class) fun readVarbytes( maxLen: Int, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/StreamSerializationContext.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/StreamSerializationContext.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/StreamSerializationContext.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/StreamSerializationContext.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Timestamp.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Timestamp.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Timestamp.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Timestamp.kt index dd72fc21d5..b44e59a73a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Timestamp.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Timestamp.kt @@ -21,15 +21,13 @@ package com.vitorpamplona.quartz.nip03Timestamp.ots import com.vitorpamplona.quartz.nip01Core.core.toHexKey -import com.vitorpamplona.quartz.nip03Timestamp.ots.Utils.arrayReverse import com.vitorpamplona.quartz.nip03Timestamp.ots.attestation.BitcoinBlockHeaderAttestation import com.vitorpamplona.quartz.nip03Timestamp.ots.attestation.TimeAttestation import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.DeserializationException import com.vitorpamplona.quartz.nip03Timestamp.ots.op.Op import com.vitorpamplona.quartz.nip03Timestamp.ots.op.OpBinary import com.vitorpamplona.quartz.utils.Hex.encode -import java.util.Collections -import java.util.TreeMap +import kotlin.jvm.JvmOverloads /** * Proof that one or more attestations commit to a message. @@ -41,7 +39,7 @@ class Timestamp( val digest: ByteArray, ) { val attestations: MutableList = ArrayList() - val ops: HashMap = HashMap() + val ops: MutableMap = mutableMapOf() /** * Create a Serialize object. @@ -61,26 +59,25 @@ class Timestamp( * @param ctx - The stream serialization context. */ fun serialize(ctx: StreamSerializationContext) { - val sortedAttestations = this.attestations // TODO: Hm, this is just a reference copy... - Collections.sort(sortedAttestations) + this.attestations.sort() - if (sortedAttestations.size > 1) { - for (i in 0.. 1) { + for (i in 0.. 1) { - val ordered = TreeMap(this.ops) + val sortedKeys = this.ops.entries.sortedBy { it.key } + val ordered = sortedKeys.associate { it.toPair() } for (entry in ordered.entries) { - val timestamp: Timestamp = entry.value!! - val op: Op = entry.key!! + val timestamp: Timestamp = entry.value + val op: Op = entry.key val curRes = op.call(this.digest) var curPar: ByteArray? = null @@ -554,16 +552,13 @@ class Timestamp( * @param setEntries - The entries set of ops hashmap * @return Returns the sorted list of map entries */ - fun sortToList(setEntries: MutableSet>): MutableList> { - val entries: MutableList> = ArrayList(setEntries) - Collections.sort( - entries, - Comparator> { a, b -> a.key.compareTo(b.key) }, + fun sortToList(setEntries: MutableSet>): List> = + setEntries.sortedWith( + Comparator> { a, b -> + a.key.compareTo(b.key) + }, ) - return entries - } - companion object { val ANSI_HEADER = "\u001B[95m" val ANSI_OKBLUE = "\u001B[94m" @@ -604,7 +599,7 @@ class Timestamp( * @param initialMsg - The initial message. * @return The deserialized Timestamp. */ - @JvmStatic + @Throws(DeserializationException::class) fun deserialize( ctx: StreamDeserializationContext, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/ICalendar.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Utils.kt similarity index 60% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/ICalendar.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Utils.kt index 8ddc0d9c52..1526bec8cb 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/ICalendar.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/Utils.kt @@ -20,20 +20,35 @@ */ package com.vitorpamplona.quartz.nip03Timestamp.ots -import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.CommitmentNotFoundException -import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.DeserializationException -import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.ExceededSizeException -import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.UrlException +/** + * Utility functions for (mostly) manipulating byte arrays. + */ +object Utils { + /** + * Compares two byte arrays. + * + * @param left the left byte array to compare with + * @param right the right byte array to compare with + * @return 0 if the arrays are identical, negative if left < right, positive if left > right + */ -interface ICalendar { - @Throws(ExceededSizeException::class, UrlException::class, DeserializationException::class) - fun submit(digest: ByteArray): Timestamp + fun compare( + left: ByteArray, + right: ByteArray, + ): Int { + var i = 0 + var j = 0 + while (i < left.size && j < right.size) { + val a = (left[i].toInt() and 0xff) + val b = (right[j].toInt() and 0xff) - @Throws( - DeserializationException::class, - ExceededSizeException::class, - CommitmentNotFoundException::class, - UrlException::class, - ) - fun getTimestamp(commitment: ByteArray): Timestamp + if (a != b) { + return a - b + } + i++ + j++ + } + + return left.size - right.size + } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/VerifyResult.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/VerifyResult.kt similarity index 76% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/VerifyResult.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/VerifyResult.kt index bdd5cb1a38..d0cf6daa5f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/VerifyResult.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/VerifyResult.kt @@ -20,11 +20,11 @@ */ package com.vitorpamplona.quartz.nip03Timestamp.ots -import android.annotation.SuppressLint -import java.text.DateFormatSymbols -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale +import kotlinx.datetime.TimeZone +import kotlinx.datetime.number +import kotlinx.datetime.toLocalDateTime +import kotlin.time.ExperimentalTime +import kotlin.time.Instant /** * Class that lets us compare, sort, store and print timestamps. @@ -38,21 +38,19 @@ class VerifyResult( /** * Returns, if existing, a string representation describing the existence of a block attest */ + @OptIn(ExperimentalTime::class) override fun toString(): String { if (height == 0 || timestamp == null) { return "" } - val pattern = "yyyy-MM-dd z" - val locale = Locale("en", "UK") - val dateFormatSymbols = DateFormatSymbols(locale) + // 1. Create an Instant from the Unix timestamp (milliseconds) + val instant = Instant.fromEpochMilliseconds(timestamp * 1000) - @SuppressLint("SimpleDateFormat") - val simpleDateFormat = - SimpleDateFormat(pattern, dateFormatSymbols) - val string = simpleDateFormat.format(Date(timestamp!! * 1000)) + // 2. Convert the Instant to a LocalDateTime in the UTC time zone + val dateTime = instant.toLocalDateTime(TimeZone.UTC) - return "block $height attests data existed as of $string" + return "block $height attests data existed as of ${dateTime.year}-${dateTime.month.number}-${dateTime.day} UTC" } override fun compareTo(other: VerifyResult): Int = this.height - other.height diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/BitcoinBlockHeaderAttestation.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/BitcoinBlockHeaderAttestation.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/BitcoinBlockHeaderAttestation.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/BitcoinBlockHeaderAttestation.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/PendingAttestation.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/PendingAttestation.kt similarity index 84% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/PendingAttestation.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/PendingAttestation.kt index 0644380fdb..202a950f96 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/PendingAttestation.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/PendingAttestation.kt @@ -20,12 +20,11 @@ */ package com.vitorpamplona.quartz.nip03Timestamp.ots.attestation -import android.util.Log import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamDeserializationContext import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamSerializationContext import com.vitorpamplona.quartz.nip03Timestamp.ots.Utils.compare import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.DeserializationException -import java.nio.charset.StandardCharsets +import com.vitorpamplona.quartz.utils.Log /** * Pending attestations. @@ -56,7 +55,7 @@ class PendingAttestation( ctx.writeVarbytes(this.uri) } - override fun toString(): String = "PendingAttestation(\'" + String(this.uri, StandardCharsets.UTF_8) + "\')" + override fun toString(): String = "PendingAttestation(\'" + uri.decodeToString() + "\')" override fun compareTo(other: TimeAttestation): Int { val opa = other as PendingAttestation @@ -97,21 +96,28 @@ class PendingAttestation( const val MAX_URI_LENGTH: Int = 1000 - const val ALLOWED_URI_CHARS: String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._/:" + val ALLOWED_URI_CHARS = + BooleanArray(128).apply { + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._/:".forEach { char -> + // The character's ASCII value is the index in the array. + this[char.code] = true + } + } fun checkUri(uri: ByteArray): Boolean { if (uri.size > MAX_URI_LENGTH) { - System.err.print("URI exceeds maximum length") + Log.w("Pending Attestation", "URI exceeds maximum length") return false } - for (i in uri.indices) { - val c = String.format("%c", uri[i])[0] - - if (ALLOWED_URI_CHARS.indexOf(c) < 0) { + // 3. Iterate through the byte array and perform a direct lookup. + for (byte in uri) { + // A direct lookup is the fastest way to check for allowed characters. + // If the byte is not in the ASCII range or not in our allowed set, return false. + val byteValue = byte.toInt() + if (byteValue < 0 || byteValue >= 128 || !ALLOWED_URI_CHARS[byteValue]) { Log.e("OpenTimestamp", "URI contains invalid character ") - return false } } @@ -119,7 +125,6 @@ class PendingAttestation( return true } - @JvmStatic @Throws(DeserializationException::class) fun deserialize(ctxPayload: StreamDeserializationContext): PendingAttestation { val utf8Uri: ByteArray diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/TimeAttestation.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/TimeAttestation.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/TimeAttestation.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/TimeAttestation.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/UnknownAttestation.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/UnknownAttestation.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/UnknownAttestation.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/attestation/UnknownAttestation.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Digest.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Digest.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Digest.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Digest.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/ExtendedDigest.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/ExtendedDigest.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/ExtendedDigest.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/ExtendedDigest.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/GeneralDigest.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/GeneralDigest.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/GeneralDigest.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/GeneralDigest.kt index 4f52a34340..e49a5e2e06 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/GeneralDigest.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/GeneralDigest.kt @@ -57,13 +57,13 @@ abstract class GeneralDigest : } protected constructor(encodedState: ByteArray) { - System.arraycopy(encodedState, 0, xBuf, 0, xBuf.size) + encodedState.copyInto(xBuf, 0, 0, xBuf.size) xBufOff = bigEndianToInt(encodedState, 4) byteCount = bigEndianToLong(encodedState, 8) } protected fun copyIn(t: GeneralDigest) { - System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.size) + t.xBuf.copyInto(xBuf, 0, 0, t.xBuf.size) xBufOff = t.xBufOff byteCount = t.byteCount @@ -152,7 +152,7 @@ abstract class GeneralDigest : } protected fun populateState(state: ByteArray) { - System.arraycopy(xBuf, 0, state, 0, xBufOff) + xBuf.copyInto(state, 0, 0, xBufOff) intToBigEndian(xBufOff, state, 4) longToBigEndian(byteCount, state, 8) } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/KeccakDigest.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/KeccakDigest.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/KeccakDigest.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/KeccakDigest.kt index 99b52fdc51..4cb2a0daa5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/KeccakDigest.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/KeccakDigest.kt @@ -20,9 +20,6 @@ */ package com.vitorpamplona.quartz.nip03Timestamp.ots.crypto -import com.vitorpamplona.quartz.nip03Timestamp.ots.Utils.arrayFill -import com.vitorpamplona.quartz.nip03Timestamp.ots.Utils.arraysCopy - /** * Implementation of Keccak based on following KeccakNISTInterface.c from http://keccak.noekeon.org/ * @@ -49,21 +46,20 @@ class KeccakDigest : ExtendedDigest { } } - @JvmOverloads constructor(bitLength: Int = 288) { init(bitLength) } constructor(source: KeccakDigest) { - System.arraycopy(source.state, 0, this.state, 0, source.state.size) - System.arraycopy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.size) + source.state.copyInto(this.state, 0, 0, source.state.size) + source.dataQueue.copyInto(this.dataQueue, 0, 0, source.dataQueue.size) this.rate = source.rate this.bitsInQueue = source.bitsInQueue this.fixedOutputLength = source.fixedOutputLength this.squeezing = source.squeezing this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing - this.chunk = arraysCopy(source.chunk) - this.oneByte = arraysCopy(source.oneByte) + this.chunk = source.chunk.copyOf() + this.oneByte = source.oneByte.copyOf() } override fun getAlgorithmName(): String = "Keccak-$fixedOutputLength" @@ -148,8 +144,8 @@ class KeccakDigest : ExtendedDigest { this.rate = rate // this is never read, need to check to see why we want to save it // this.capacity = capacity; - arrayFill(this.state, 0.toByte()) - arrayFill(this.dataQueue, 0.toByte()) + this.state.fill(0.toByte()) + this.dataQueue.fill(0.toByte()) this.bitsInQueue = 0 this.squeezing = false this.bitsAvailableForSqueezing = 0 @@ -184,12 +180,12 @@ class KeccakDigest : ExtendedDigest { j = 0 while (j < wholeBlocks) { - System.arraycopy( - data, - (off + (i / 8) + (j * chunk.size)).toInt(), - chunk, - 0, - chunk.size, + val index = (off + (i / 8) + (j * chunk.size)).toInt() + data.copyInto( + destination = chunk, + destinationOffset = 0, + startIndex = index, + endIndex = index + chunk.size, ) // displayIntermediateValues.displayBytes(1, "Block to be absorbed", curData, rate / 8); @@ -207,12 +203,13 @@ class KeccakDigest : ExtendedDigest { val partialByte = partialBlock % 8 partialBlock -= partialByte - System.arraycopy( - data, - off + (i / 8).toInt(), - dataQueue, - bitsInQueue / 8, - partialBlock / 8, + + val index = off + (i / 8).toInt() + data.copyInto( + destination = dataQueue, + destinationOffset = bitsInQueue / 8, + startIndex = off + (i / 8).toInt(), + endIndex = index + partialBlock / 8, ) bitsInQueue += partialBlock @@ -298,12 +295,11 @@ class KeccakDigest : ExtendedDigest { partialBlock = (outputLength - i).toInt() } - System.arraycopy( - dataQueue, - (rate - bitsAvailableForSqueezing) / 8, + dataQueue.copyInto( output, offset + (i / 8).toInt(), - partialBlock / 8, + (rate - bitsAvailableForSqueezing) / 8, + (rate - bitsAvailableForSqueezing) / 8 + partialBlock / 8, ) bitsAvailableForSqueezing -= partialBlock i += partialBlock.toLong() @@ -423,7 +419,7 @@ class KeccakDigest : ExtendedDigest { var tempA: LongArray = LongArray(25) private fun pi(array: LongArray) { - System.arraycopy(array, 0, tempA, 0, tempA.size) + array.copyInto(tempA, 0, 0, tempA.size) for (x in 0..4) { for (y in 0..4) { @@ -467,7 +463,7 @@ class KeccakDigest : ExtendedDigest { byteState: ByteArray, data: ByteArray, ) { - System.arraycopy(byteState, 0, data, 0, 128) + byteState.copyInto(data, 0, 0, 128) } private fun keccakExtract( @@ -475,7 +471,7 @@ class KeccakDigest : ExtendedDigest { data: ByteArray, laneCount: Int, ) { - System.arraycopy(byteState, 0, data, 0, laneCount * 8) + byteState.copyInto(data, 0, 0, laneCount * 8) } companion object { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Memoable.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Memoable.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Memoable.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Memoable.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Pack.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Pack.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Pack.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Pack.kt index 77ac393621..20dad9a4f7 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Pack.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/Pack.kt @@ -34,7 +34,6 @@ object Pack { return n.toShort() } - @JvmStatic fun bigEndianToInt( bs: ByteArray, off: Int, @@ -65,7 +64,6 @@ object Pack { return bs } - @JvmStatic fun intToBigEndian( n: Int, bs: ByteArray, @@ -96,7 +94,6 @@ object Pack { } } - @JvmStatic fun bigEndianToLong( bs: ByteArray, off: Int, @@ -124,7 +121,6 @@ object Pack { return bs } - @JvmStatic fun longToBigEndian( n: Long, bs: ByteArray, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/RIPEMD160Digest.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/RIPEMD160Digest.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/RIPEMD160Digest.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/RIPEMD160Digest.kt index 869c82365f..830fdfe6bb 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/RIPEMD160Digest.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/crypto/RIPEMD160Digest.kt @@ -60,7 +60,7 @@ class RIPEMD160Digest : GeneralDigest { h3 = t.h3 h4 = t.h4 - System.arraycopy(t.xArray, 0, xArray, 0, t.xArray.size) + t.xArray.copyInto(xArray, 0, 0, t.xArray.size) xOff = t.xOff } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/CommitmentNotFoundException.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/CommitmentNotFoundException.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/CommitmentNotFoundException.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/CommitmentNotFoundException.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/DeserializationException.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/DeserializationException.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/DeserializationException.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/DeserializationException.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/ExceededSizeException.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/ExceededSizeException.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/ExceededSizeException.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/ExceededSizeException.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/UrlException.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/UrlException.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/UrlException.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/UrlException.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/VerificationException.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/VerificationException.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/VerificationException.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/exceptions/VerificationException.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/Op.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/Op.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/Op.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/Op.kt index 7ec89956f5..9d7e6db3e8 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/Op.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/Op.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.quartz.nip03Timestamp.ots.op -import android.util.Log import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamDeserializationContext import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamSerializationContext import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.DeserializationException +import com.vitorpamplona.quartz.utils.Log /** * Operations are the edges in the timestamp tree, with each operation taking a message and zero or more arguments to produce a result. @@ -153,7 +153,7 @@ abstract class Op : Comparable { } else { Log.e( "OpenTimestamp", - "Unknown operation tag: " + tag + " 0x" + String.format("%02x", tag), + "Unknown operation tag: " + tag + " 0x" + tag.toHexString(), ) return null // TODO: Is this OK? Won't it blow up later? Better to throw? } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpAppend.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpAppend.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpAppend.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpAppend.kt index 2d5608b8ad..bab1302d09 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpAppend.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpAppend.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.quartz.nip03Timestamp.ots.op import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamDeserializationContext -import com.vitorpamplona.quartz.nip03Timestamp.ots.Utils.arraysConcat import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.DeserializationException /** @@ -36,7 +35,7 @@ class OpAppend( override fun tagName(): String = "append" - public override fun call(msg: ByteArray): ByteArray = arraysConcat(msg, this.arg) + public override fun call(msg: ByteArray): ByteArray = msg + this.arg override fun equals(other: Any?): Boolean { if (other !is OpAppend) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpBinary.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpBinary.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpBinary.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpBinary.kt index 323c24c1d6..5a8b69b7e3 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpBinary.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpBinary.kt @@ -20,12 +20,12 @@ */ package com.vitorpamplona.quartz.nip03Timestamp.ots.op -import android.util.Log import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamDeserializationContext import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamSerializationContext import com.vitorpamplona.quartz.nip03Timestamp.ots.Utils.compare import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.DeserializationException import com.vitorpamplona.quartz.utils.Hex.encode +import com.vitorpamplona.quartz.utils.Log /** * Operations that act on a message and a single argument. @@ -56,7 +56,6 @@ abstract class OpBinary( override fun hashCode(): Int = TAG.toInt() xor this.arg.contentHashCode() companion object { - @JvmStatic @Throws(DeserializationException::class) fun deserializeFromTag( ctx: StreamDeserializationContext, @@ -71,7 +70,7 @@ abstract class OpBinary( } else { Log.e( "OpenTimestamp", - "Unknown operation tag: " + tag + " 0x" + String.format("%02x", tag), + "Unknown operation tag: " + tag + " 0x" + tag.toHexString(), ) return null // TODO: Is this OK? Won't it blow up later? Better to throw? } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpCrypto.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpCrypto.kt similarity index 60% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpCrypto.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpCrypto.kt index 9675a8fe13..858c48ad37 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpCrypto.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpCrypto.kt @@ -20,14 +20,8 @@ */ package com.vitorpamplona.quartz.nip03Timestamp.ots.op -import android.util.Log import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamDeserializationContext -import java.io.File -import java.io.FileInputStream -import java.io.IOException -import java.io.InputStream -import java.security.MessageDigest -import java.security.NoSuchAlgorithmException +import com.vitorpamplona.quartz.utils.diggest.DigestInstance /** * Cryptographic transformations. @@ -44,22 +38,14 @@ abstract class OpCrypto internal constructor() : OpUnary() { override fun call(msg: ByteArray): ByteArray { // For Sha1 & Sha256 use java.security.MessageDigest library - try { - val digest = MessageDigest.getInstance(this.hashLibName()) - val hash = digest.digest(msg) + val digest = DigestInstance(this.hashLibName()) + val hash = digest.digest(msg) - return hash - } catch (e: NoSuchAlgorithmException) { - Log.e("OpenTimestamp", "NoSuchAlgorithmException") - e.printStackTrace() - - return byteArrayOf() // TODO: Is this OK? Won't it blow up later? Better to throw? - } + return hash } - @Throws(NoSuchAlgorithmException::class) fun hashFd(ctx: StreamDeserializationContext): ByteArray { - val digest = MessageDigest.getInstance(this.hashLibName()) + val digest = DigestInstance(this.hashLibName()) var chunk = ctx.read(1048576) while (chunk.isNotEmpty()) { @@ -72,36 +58,13 @@ abstract class OpCrypto internal constructor() : OpUnary() { return hash } - @Throws(IOException::class, NoSuchAlgorithmException::class) - fun hashFd(file: File?): ByteArray = FileInputStream(file).use { inputStream -> hashFd(inputStream) } - - @Throws(IOException::class, NoSuchAlgorithmException::class) fun hashFd(bytes: ByteArray): ByteArray { val ctx = StreamDeserializationContext(bytes) return hashFd(ctx) } - @Throws(IOException::class, NoSuchAlgorithmException::class) - fun hashFd(inputStream: InputStream): ByteArray { - val digest = MessageDigest.getInstance(this.hashLibName()) - val chunk = ByteArray(1048576) - var count = inputStream.read(chunk, 0, 1048576) - - while (count >= 0) { - digest.update(chunk, 0, count) - count = inputStream.read(chunk, 0, 1048576) - } - - // TODO: Is this needed? Closing of stream should be callers responsibility? - inputStream.close() - val hash = digest.digest() - - return hash - } - companion object { - @JvmStatic fun deserializeFromTag( ctx: StreamDeserializationContext, tag: Byte, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpKECCAK256.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpKECCAK256.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpKECCAK256.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpKECCAK256.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpPrepend.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpPrepend.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpPrepend.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpPrepend.kt index e88d1c6b37..d26af71f82 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpPrepend.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpPrepend.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.quartz.nip03Timestamp.ots.op import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamDeserializationContext -import com.vitorpamplona.quartz.nip03Timestamp.ots.Utils.arraysConcat import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.DeserializationException /** @@ -36,7 +35,7 @@ class OpPrepend( override fun tagName(): String = "prepend" - public override fun call(msg: ByteArray): ByteArray = arraysConcat(this.arg, msg) + public override fun call(msg: ByteArray): ByteArray = this.arg + msg override fun equals(other: Any?): Boolean { if (other !is OpPrepend) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpRIPEMD160.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpRIPEMD160.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpRIPEMD160.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpRIPEMD160.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpSHA1.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpSHA1.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpSHA1.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpSHA1.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpSHA256.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpSHA256.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpSHA256.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpSHA256.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpUnary.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpUnary.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpUnary.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpUnary.kt index bdd23920b8..3bd2e4ba20 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpUnary.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/op/OpUnary.kt @@ -20,8 +20,8 @@ */ package com.vitorpamplona.quartz.nip03Timestamp.ots.op -import android.util.Log import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamDeserializationContext +import com.vitorpamplona.quartz.utils.Log /** * Operations that act on a single message. diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/tags/TargetEventKindTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/tags/TargetEventKindTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/tags/TargetEventKindTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/tags/TargetEventKindTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/tags/TargetEventTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/tags/TargetEventTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/tags/TargetEventTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/tags/TargetEventTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/PrivateDMCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/PrivateDMCache.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/PrivateDMCache.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/PrivateDMCache.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/EncryptedInfo.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/EncryptedInfo.kt similarity index 87% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/EncryptedInfo.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/EncryptedInfo.kt index 096b5be660..7583874b3e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/EncryptedInfo.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/EncryptedInfo.kt @@ -20,8 +20,8 @@ */ package com.vitorpamplona.quartz.nip04Dm.crypto -import android.util.Log -import java.util.Base64 +import com.vitorpamplona.quartz.utils.Log +import kotlin.io.encoding.Base64 class EncryptedInfo( val ciphertext: ByteArray, @@ -48,8 +48,8 @@ class EncryptedInfo( ciphertext: ByteArray, nonce: ByteArray, ): String { - val nonceB64 = Base64.getEncoder().encodeToString(nonce) - val ciphertextB64 = Base64.getEncoder().encodeToString(ciphertext) + val nonceB64 = Base64.encode(nonce) + val ciphertextB64 = Base64.encode(ciphertext) return "$ciphertextB64?iv=$nonceB64" } @@ -58,8 +58,8 @@ class EncryptedInfo( // cleaning up some bug from some client. val parts = payload.removeSuffix("-null").split("?iv=") EncryptedInfo( - ciphertext = Base64.getDecoder().decode(parts[0]), - nonce = Base64.getDecoder().decode(parts[1]), + ciphertext = Base64.decode(parts[0]), + nonce = Base64.decode(parts[1]), ) } catch (e: Exception) { Log.w("NIP04", "Unable to Parse encrypted payload: $payload") diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/Encryption.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/Encryption.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/Encryption.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/Encryption.kt index 6fce192d1b..4576f8b10b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/Encryption.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/Encryption.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.quartz.nip04Dm.crypto import com.vitorpamplona.quartz.utils.RandomInstance import com.vitorpamplona.quartz.utils.Secp256k1Instance +import com.vitorpamplona.quartz.utils.ciphers.AESCBC class Encryption { fun encrypt( @@ -46,7 +47,7 @@ class Encryption { sharedSecret: ByteArray, ): EncryptedInfo { val iv = RandomInstance.bytes(16) - return EncryptedInfo(AESCBC(sharedSecret, iv).encrypt(msg.toByteArray()), iv) + return EncryptedInfo(AESCBC(sharedSecret, iv).encrypt(msg.encodeToByteArray()), iv) } fun decrypt( @@ -67,7 +68,7 @@ class Encryption { encryptedMsg: ByteArray, iv: ByteArray, sharedSecret: ByteArray, - ): String = String(AESCBC(sharedSecret, iv).decrypt(encryptedMsg)) + ): String = AESCBC(sharedSecret, iv).decrypt(encryptedMsg).decodeToString() fun computeSharedSecret( privateKey: ByteArray, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/Nip04.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/Nip04.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/Nip04.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/Nip04.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/messages/PrivateDmEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/messages/PrivateDmEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/messages/PrivateDmEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/messages/PrivateDmEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/messages/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/messages/TagArrayBuilderExt.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/messages/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/messages/TagArrayBuilderExt.kt index e37f0439d9..5a49293009 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/messages/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip04Dm/messages/TagArrayBuilderExt.kt @@ -24,6 +24,7 @@ import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.tags.events.EventReference import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag +import com.vitorpamplona.quartz.nip10Notes.tags.toMarkedETag fun TagArrayBuilder.reply(tag: EventReference) = add(MarkedETag.assemble(tag.eventId, tag.relayHint, MarkedETag.MARKER.REPLY, tag.author)) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/Nip05.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/Nip05.kt similarity index 75% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/Nip05.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/Nip05.kt index eb9404e142..c390be19fd 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/Nip05.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/Nip05.kt @@ -20,8 +20,11 @@ */ package com.vitorpamplona.quartz.nip05DnsIdentifiers -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive class Nip05 { fun assembleUrl(nip05address: String): String? { @@ -41,17 +44,6 @@ class Nip05 { nip05: String, returnBody: String, ): Result { - // NIP05 usernames are case insensitive, but JSON properties are not - // converts the json to lowercase and then tries to access the username via a - // lowercase version of the username. - val nip05url = - try { - JsonMapper.mapper.readTree(returnBody.lowercase()) - } catch (e: Throwable) { - if (e is CancellationException) throw e - return Result.failure(e) - } - val parts = nip05.split("@") val user = if (parts.size == 2) { @@ -60,8 +52,21 @@ class Nip05 { "_" } - val hexKey = nip05url?.get("names")?.get(user)?.asText() - - return Result.success(hexKey) + // NIP05 usernames are case insensitive, but JSON properties are not + // converts the json to lowercase and then tries to access the username via a + // lowercase version of the username. + return try { + val rootElement = Json.parseToJsonElement(returnBody.lowercase()) + val hexKey = + rootElement.jsonObject["names"] + ?.jsonObject[user] + ?.jsonPrimitive + ?.content + Result.success(hexKey) + } catch (e: Throwable) { + if (e is CancellationException) throw e + Log.w("Nip05", "Unable to Parse NIP-05 for $nip05 with $returnBody", e) + Result.failure(e) + } } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip32SeedDerivation.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip32SeedDerivation.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip32SeedDerivation.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip32SeedDerivation.kt index 6a72a0291e..f34a195b84 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip32SeedDerivation.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip32SeedDerivation.kt @@ -20,8 +20,9 @@ */ package com.vitorpamplona.quartz.nip06KeyDerivation +import androidx.compose.runtime.key import com.vitorpamplona.quartz.utils.Secp256k1Instance -import com.vitorpamplona.quartz.utils.hmac512 +import com.vitorpamplona.quartz.utils.mac.MacInstance /* Simplified from: https://github.com/ACINQ/bitcoin-kmp/ @@ -32,6 +33,15 @@ class Bip32SeedDerivation { val chaincode: ByteArray, ) + fun hmac512( + key: ByteArray, + data: ByteArray, + ): ByteArray { + val mac = MacInstance("HmacSHA512", key) + mac.update(data) + return mac.doFinal() + } + /** * @param seed random seed * @return a "master" private key diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39KeyPath.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39KeyPath.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39KeyPath.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39KeyPath.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39Mnemonics.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39Mnemonics.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39Mnemonics.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Bip39Mnemonics.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Nip06.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Nip06.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Nip06.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip06KeyDerivation/Nip06.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt index 96d655716c..4d313572d8 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionEvent.kt @@ -28,9 +28,9 @@ import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.aTag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.taggedAddresses +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.aTag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.taggedAddresses import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.events.eTag import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEventIds diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionIndex.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionIndex.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionIndex.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionIndex.kt index 7e0e0e1618..361c24512b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionIndex.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip09Deletions/DeletionIndex.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.quartz.nip09Deletions import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.verify -import com.vitorpamplona.quartz.utils.LargeCache +import com.vitorpamplona.quartz.nip01Core.crypto.verify +import com.vitorpamplona.quartz.utils.cache.LargeCache class DeletionIndex { data class DeletionRequest( diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/BaseNoteEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/BaseNoteEvent.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/BaseNoteEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/BaseNoteEvent.kt index 8b02fc2bbb..f601ab8de0 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/BaseNoteEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/BaseNoteEvent.kt @@ -44,13 +44,16 @@ open class BaseNoteEvent( content: String, sig: HexKey, ) : Event(id, pubKey, createdAt, kind, tags, content, sig) { - @Transient + @kotlinx.serialization.Transient + @kotlin.jvm.Transient private var citedUsersCache: Set? = null - @Transient + @kotlinx.serialization.Transient + @kotlin.jvm.Transient private var citedNotesCache: Set? = null - @Transient + @kotlinx.serialization.Transient + @kotlin.jvm.Transient private var citedNIP19Cache: List? = null fun citedNIP19(): List { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/BaseThreadedEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/BaseThreadedEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/BaseThreadedEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/BaseThreadedEvent.kt index 92ec393ef7..e58c8d1ce5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/BaseThreadedEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/BaseThreadedEvent.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.quartz.nip10Notes import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.tags.addressables.taggedATags +import com.vitorpamplona.quartz.nip01Core.tags.aTag.taggedATags import com.vitorpamplona.quartz.nip01Core.tags.people.taggedUsers import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/TextNoteEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/TextNoteEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/TextNoteEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/TextNoteEvent.kt index 5628336f5d..f50a5dd489 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/TextNoteEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/TextNoteEvent.kt @@ -31,7 +31,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag import com.vitorpamplona.quartz.nip10Notes.tags.markedETags diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/ContentHashTags.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/ContentHashTags.kt similarity index 86% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/ContentHashTags.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/ContentHashTags.kt index e75924a1fc..060062de98 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/ContentHashTags.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/ContentHashTags.kt @@ -20,9 +20,7 @@ */ package com.vitorpamplona.quartz.nip10Notes.content -import java.util.regex.Pattern - -val hashtagSearch = Pattern.compile("(?:\\s|\\A)#([^\\s!@#\$%^&*()=+./,\\[{\\]};:'\"?><]+)") +val hashtagSearch = Regex("(?:\\s|\\A)#([^\\s!@#\$%^&*()=+./,\\[{\\]};:'\"?><]+)") fun findHashtags( content: String, @@ -30,10 +28,10 @@ fun findHashtags( ): List { if (content.isBlank()) return emptyList() - val matcher = hashtagSearch.matcher(content) - while (matcher.find()) { + val matcher = hashtagSearch.findAll(content) + matcher.forEach { try { - val tag = matcher.group(1) + val tag = it.groups[1]?.value if (tag != null && tag.isNotBlank()) { output.add(tag) } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/IndexedTags.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/IndexedTags.kt similarity index 86% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/IndexedTags.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/IndexedTags.kt index 6b0d007dd8..6a4aa324d7 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/IndexedTags.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/IndexedTags.kt @@ -21,13 +21,12 @@ package com.vitorpamplona.quartz.nip10Notes.content import com.vitorpamplona.quartz.nip01Core.core.TagArray -import java.util.regex.Pattern /** * this is the old way of linking an e tag on the content by [index] the tag */ -val tagSearch = Pattern.compile("(?:\\s|\\A)\\#\\[([0-9]+)\\]") +val tagSearch = Regex("(?:\\s|\\A)\\#\\[([0-9]+)\\]") /** * Returns the old-style [1] tag that pionts to an index in the tag array @@ -37,10 +36,10 @@ fun findIndexTagsWithPeople( tags: TagArray, output: MutableSet = mutableSetOf(), ): List { - val matcher = tagSearch.matcher(content) - while (matcher.find()) { + val matcher = tagSearch.findAll(content) + matcher.forEach { index -> try { - val tag = matcher.group(1)?.let { tags[it.toInt()] } + val tag = index.groups[1]?.value?.let { tags[it.toInt()] } if (tag != null && tag.size > 1 && tag[0] == "p") { output.add(tag[1]) } @@ -59,10 +58,10 @@ fun findIndexTagsWithEventsOrAddresses( tags: TagArray, output: MutableSet = mutableSetOf(), ): Set { - val matcher = tagSearch.matcher(content) - while (matcher.find()) { + val matcher = tagSearch.findAll(content) + matcher.forEach { index -> try { - val tag = matcher.group(1)?.let { tags[it.toInt()] } + val tag = index.groups[1]?.value?.let { tags[it.toInt()] } if (tag != null && tag.size > 1 && tag[0] == "e") { output.add(tag[1]) } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/NostrUris.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/NostrUris.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/NostrUris.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/NostrUris.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/Urls.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/Urls.kt similarity index 82% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/Urls.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/Urls.kt index 6969635099..7b2543af5b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/Urls.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/content/Urls.kt @@ -20,11 +20,10 @@ */ package com.vitorpamplona.quartz.nip10Notes.content -import com.linkedin.urls.detection.UrlDetector -import com.linkedin.urls.detection.UrlDetectorOptions -import com.vitorpamplona.quartz.nip96FileStorage.HttpUrlFormatter +import com.vitorpamplona.quartz.nip01Core.tags.references.HttpUrlFormatter +import com.vitorpamplona.quartz.utils.fastFindURLs -fun findURLs(text: String): List = UrlDetector(text, UrlDetectorOptions.Default).detect().map { it.originalUrl } +fun findURLs(text: String) = fastFindURLs(text) fun buildUrlRefs(urls: List): List> = urls diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/MarkedETag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/MarkedETag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/MarkedETag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/MarkedETag.kt index d5b2a85dca..ef1907ebcb 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/MarkedETag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/MarkedETag.kt @@ -21,8 +21,10 @@ package com.vitorpamplona.quartz.nip10Notes.tags import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.has +import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer @@ -85,7 +87,6 @@ data class MarkedETag( key: HexKey, ) = tag.size >= 2 && tag[0] == TAG_NAME && tag[1] == key - @JvmStatic fun parse(tag: Array): MarkedETag? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -100,7 +101,6 @@ data class MarkedETag( ) } - @JvmStatic fun parseId(tag: Array): HexKey? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -119,7 +119,6 @@ data class MarkedETag( // pubkey marker ["e", "id", "pubkey"] // incorrect // current root ["e", "id", "marker"] // incorrect - @JvmStatic private fun pickRelayHint(tag: Array): NormalizedRelayUrl? { if (tag.has(2) && tag[2].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[2])) return RelayUrlNormalizer.normalizeOrNull(tag[2]) if (tag.has(3) && tag[3].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[3])) return RelayUrlNormalizer.normalizeOrNull(tag[3]) @@ -127,7 +126,6 @@ data class MarkedETag( return null } - @JvmStatic private fun pickAuthor(tag: Array): HexKey? { if (tag.has(3) && tag[3].length == 64) return tag[3] if (tag.has(4) && tag[4].length == 64) return tag[4] @@ -135,7 +133,6 @@ data class MarkedETag( return null } - @JvmStatic private fun pickMarker(tag: Array): MARKER? { if (tag.has(3)) MARKER.parse(tag[3])?.let { return it } if (tag.has(4)) MARKER.parse(tag[4])?.let { return it } @@ -143,7 +140,6 @@ data class MarkedETag( return null } - @JvmStatic fun parseAllThreadTags(tag: Array): MarkedETag? = if (tag.size >= 2 && tag[0] == TAG_NAME) { MarkedETag( @@ -156,7 +152,6 @@ data class MarkedETag( null } - @JvmStatic fun parseOnlyPositionalThreadTagsIds(tag: Array): HexKey? = if (tag.size >= 2 && tag[0] == TAG_NAME) { if (tag.size <= 3) { @@ -186,7 +181,6 @@ data class MarkedETag( null } - @JvmStatic fun parseAsHint(tag: Array): EventIdHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -198,7 +192,6 @@ data class MarkedETag( return EventIdHint(tag[1], hint) } - @JvmStatic fun parseRoot(tag: Array): MarkedETag? { ensure(tag.has(3)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -218,7 +211,7 @@ data class MarkedETag( /** * Old positional arguments */ - @JvmStatic + fun parseUnmarkedRoot(tag: Array): MarkedETag? = if (tag.size in 2..3 && tag[0] == TAG_NAME) { MarkedETag(tag[1], pickRelayHint(tag), MARKER.ROOT) @@ -226,7 +219,6 @@ data class MarkedETag( null } - @JvmStatic fun parseReply(tag: Array): MarkedETag? { ensure(tag.has(3)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -246,7 +238,7 @@ data class MarkedETag( /** * Old positional arguments */ - @JvmStatic + fun parseUnmarkedReply(tag: Array): MarkedETag? = if (tag.size in 2..3 && tag[0] == TAG_NAME) { MarkedETag(tag[1], pickRelayHint(tag), MARKER.REPLY) @@ -254,7 +246,6 @@ data class MarkedETag( null } - @JvmStatic fun parseRootId(tag: Array): HexKey? { ensure(tag.has(3)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -266,7 +257,6 @@ data class MarkedETag( return tag[1] } - @JvmStatic fun assemble( eventId: HexKey, relay: NormalizedRelayUrl?, @@ -274,7 +264,6 @@ data class MarkedETag( author: HexKey?, ) = arrayOfNotNull(TAG_NAME, eventId, relay?.url, marker, author) - @JvmStatic fun assemble( eventId: HexKey, relay: NormalizedRelayUrl?, @@ -283,3 +272,5 @@ data class MarkedETag( ) = assemble(eventId, relay, marker?.code, author) } } + +fun EventHintBundle.toMarkedETag(marker: MarkedETag.MARKER) = MarkedETag(event.id, relay, marker, event.pubKey) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/Positional.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/Positional.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/Positional.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/Positional.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/ReplyBuilder.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/ReplyBuilder.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/ReplyBuilder.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/ReplyBuilder.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip10Notes/tags/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip11RelayInfo/Nip11RelayInformation.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip11RelayInfo/Nip11RelayInformation.kt similarity index 85% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip11RelayInfo/Nip11RelayInformation.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip11RelayInfo/Nip11RelayInformation.kt index cccbde429b..fce0f2b4ed 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip11RelayInfo/Nip11RelayInformation.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip11RelayInfo/Nip11RelayInformation.kt @@ -21,10 +21,10 @@ package com.vitorpamplona.quartz.nip11RelayInfo import androidx.compose.runtime.Stable -import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.vitorpamplona.quartz.nip01Core.core.JsonMapper +import kotlinx.serialization.Serializable -@Stable +@Serializable class Nip11RelayInformation( val id: String? = null, val name: String? = null, @@ -47,16 +47,12 @@ class Nip11RelayInformation( val nip50: List? = null, ) { companion object { - val mapper = - jacksonObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true) - - fun fromJson(json: String): Nip11RelayInformation = mapper.readValue(json, Nip11RelayInformation::class.java) + fun fromJson(json: String): Nip11RelayInformation = JsonMapper.fromJson(json) } } @Stable +@Serializable class RelayInformationFee( val amount: Int? = null, val unit: String? = null, @@ -64,12 +60,14 @@ class RelayInformationFee( val kinds: List? = null, ) +@Serializable class RelayInformationFees( val admission: List? = null, val subscription: List? = null, val publication: List? = null, ) +@Serializable class RelayInformationLimitation( val max_message_length: Int? = null, val max_subscriptions: Int? = null, @@ -87,8 +85,9 @@ class RelayInformationLimitation( val created_at_upper_limit: Int? = null, ) +@Serializable class RelayInformationRetentionData( val kinds: ArrayList? = null, - val tiem: Int? = null, + val time: Int? = null, val count: Int? = null, ) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/ByteArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/ByteArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/ByteArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/ByteArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/MiningBuffer.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/MiningBuffer.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/MiningBuffer.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/MiningBuffer.kt index a449b48a03..463b712516 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/MiningBuffer.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/MiningBuffer.kt @@ -25,5 +25,5 @@ class MiningBuffer( val nonceStarts: Int, val nonceEnds: Int, ) { - fun nonce() = String(bytes.copyOfRange(nonceStarts, nonceEnds)) + fun nonce() = bytes.copyOfRange(nonceStarts, nonceEnds).decodeToString() } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/PoWMiner.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/PoWMiner.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/PoWMiner.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/PoWMiner.kt index 22b4ca1902..7ff5f18251 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/PoWMiner.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/PoWMiner.kt @@ -22,19 +22,18 @@ package com.vitorpamplona.quartz.nip13Pow.miner import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.crypto.EventHasher +import com.vitorpamplona.quartz.nip01Core.crypto.EventHasherSerializer import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate import com.vitorpamplona.quartz.nip13Pow.tags.PoWTag -import com.vitorpamplona.quartz.utils.sha256.Sha256Hasher +import com.vitorpamplona.quartz.utils.sha256.sha256 class PoWMiner( val buffer: MiningBuffer, val desiredPoW: Int, ) { - val hasher = Sha256Hasher() val emptyBytesForDesiredPoW = desiredPoW / 8 - fun reachedDesiredPoW(byteArray: ByteArray) = PoWRankEvaluator.atLeastPowRank(hasher.hash(byteArray), desiredPoW, emptyBytesForDesiredPoW) + fun reachedDesiredPoW(byteArray: ByteArray) = PoWRankEvaluator.atLeastPowRank(sha256(byteArray), desiredPoW, emptyBytesForDesiredPoW) fun run() = runDigit(buffer.nonceStarts) @@ -78,7 +77,7 @@ class PoWMiner( val initialNonce = randomBase(nextSize) val bytes = - EventHasher + EventHasherSerializer .fastMakeJsonForId( pubKey = pubKey, createdAt = template.createdAt, @@ -87,7 +86,7 @@ class PoWMiner( content = template.content, ) - val startIndex = bytes.indexOf(initialNonce.toByteArray()) + val startIndex = bytes.indexOf(initialNonce.encodeToByteArray()) val buffer = MiningBuffer(bytes, startIndex, startIndex + nextSize) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/PoWRankEvaluator.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/PoWRankEvaluator.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/PoWRankEvaluator.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/PoWRankEvaluator.kt index 61396fe8f4..6c63630727 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/PoWRankEvaluator.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/miner/PoWRankEvaluator.kt @@ -34,7 +34,6 @@ class PoWRankEvaluator { const val R1 = 0b01000000.toByte() const val NEGATIVE = 0b10000000.toByte() - @JvmStatic fun compute( id: HexKey, commitedPoW: Int?, @@ -52,7 +51,6 @@ class PoWRankEvaluator { } } - @JvmStatic fun calculatePowRankOf(id: HexKey): Int { var rank = 0 for (i in 0..id.length) { @@ -74,7 +72,6 @@ class PoWRankEvaluator { return rank } - @JvmStatic fun calculatePowRankOf(id: ByteArray): Int { var rank = 0 for (byte in id) { @@ -104,7 +101,6 @@ class PoWRankEvaluator { return rank } - @JvmStatic fun atLeastPowRank( id: ByteArray, minPoW: Int, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/tags/PoWTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/tags/PoWTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/tags/PoWTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/tags/PoWTag.kt index f8f241b5f4..b5a526efbe 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip13Pow/tags/PoWTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip13Pow/tags/PoWTag.kt @@ -37,10 +37,8 @@ class PoWTag( companion object { const val TAG_NAME = "nonce" - @JvmStatic fun hasTagWithContent(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun parse(tag: Array): PoWTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -48,7 +46,6 @@ class PoWTag( return PoWTag(tag[1], tag.getOrNull(2)?.toIntOrNull()) } - @JvmStatic fun parseCommitment(tag: Array): Int? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -56,7 +53,6 @@ class PoWTag( return tag.getOrNull(2)?.toIntOrNull() } - @JvmStatic fun assemble( nonce: String, commitment: Int?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip14Subject/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip14Subject/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip14Subject/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip14Subject/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip14Subject/SubjectTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip14Subject/SubjectTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip14Subject/SubjectTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip14Subject/SubjectTag.kt index e6ff0b8b83..0bdf27a460 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip14Subject/SubjectTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip14Subject/SubjectTag.kt @@ -27,10 +27,8 @@ class SubjectTag { companion object { const val TAG_NAME = "subject" - @JvmStatic fun hasTagWithContent(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -38,7 +36,6 @@ class SubjectTag { return tag[1] } - @JvmStatic fun assemble(subject: String) = arrayOf(TAG_NAME, subject) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip14Subject/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip14Subject/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip14Subject/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip14Subject/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip14Subject/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip14Subject/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip14Subject/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip14Subject/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/NIP17Factory.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/NIP17Factory.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/NIP17Factory.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/NIP17Factory.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/BaseDMGroupEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/BaseDMGroupEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/BaseDMGroupEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/BaseDMGroupEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/ChatroomKey.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/ChatroomKey.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/ChatroomKey.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/ChatroomKey.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/ChatroomKeyable.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/ChatroomKeyable.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/ChatroomKeyable.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/ChatroomKeyable.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/NIP17Group.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/NIP17Group.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/NIP17Group.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/base/NIP17Group.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/ChatMessageEncryptedFileHeaderEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/ChatMessageEncryptedFileHeaderEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/ChatMessageEncryptedFileHeaderEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/ChatMessageEncryptedFileHeaderEvent.kt index fb11f2ff66..7570e9864e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/ChatMessageEncryptedFileHeaderEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/ChatMessageEncryptedFileHeaderEvent.kt @@ -28,7 +28,6 @@ import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip17Dm.base.BaseDMGroupEvent -import com.vitorpamplona.quartz.nip17Dm.files.encryption.AESGCM import com.vitorpamplona.quartz.nip17Dm.files.tags.EncryptionAlgo import com.vitorpamplona.quartz.nip17Dm.files.tags.EncryptionKey import com.vitorpamplona.quartz.nip17Dm.files.tags.EncryptionNonce @@ -41,6 +40,7 @@ import com.vitorpamplona.quartz.nip94FileMetadata.tags.HashSha256Tag import com.vitorpamplona.quartz.nip94FileMetadata.tags.OriginalHashTag import com.vitorpamplona.quartz.nip94FileMetadata.tags.SizeTag import com.vitorpamplona.quartz.utils.TimeUtils +import com.vitorpamplona.quartz.utils.ciphers.AESGCM @Immutable class ChatMessageEncryptedFileHeaderEvent( diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/TagArrayBuilderExt.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/TagArrayBuilderExt.kt index 210becd6de..8fe1ba3557 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/TagArrayBuilderExt.kt @@ -27,6 +27,7 @@ import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTags import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag +import com.vitorpamplona.quartz.nip10Notes.tags.toMarkedETag import com.vitorpamplona.quartz.nip17Dm.files.tags.EncryptionAlgo import com.vitorpamplona.quartz.nip17Dm.files.tags.EncryptionKey import com.vitorpamplona.quartz.nip17Dm.files.tags.EncryptionNonce diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionAlgo.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionAlgo.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionAlgo.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionAlgo.kt index b7dce56743..496240a780 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionAlgo.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionAlgo.kt @@ -27,10 +27,8 @@ class EncryptionAlgo { companion object { const val TAG_NAME = "encryption-algorithm" - @JvmStatic fun isTag(tag: Array) = tag.has(1) && tag[0] == TAG_NAME - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -38,7 +36,6 @@ class EncryptionAlgo { return tag[1] } - @JvmStatic fun assemble(excerpt: String) = arrayOf(TAG_NAME, excerpt) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionKey.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionKey.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionKey.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionKey.kt index 935ed37aa8..1a9fb42bfd 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionKey.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionKey.kt @@ -29,10 +29,8 @@ class EncryptionKey { companion object { const val TAG_NAME = "decryption-key" - @JvmStatic fun isTag(tag: Array) = tag.has(0) && tag[0] == TAG_NAME - @JvmStatic fun parse(tag: Array): ByteArray? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -40,7 +38,6 @@ class EncryptionKey { return runCatching { tag[1].hexToByteArray() }.getOrNull() } - @JvmStatic fun assemble(key: ByteArray) = arrayOf(TAG_NAME, key.toHexKey()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionNonce.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionNonce.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionNonce.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionNonce.kt index f311808246..2703f78074 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionNonce.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/EncryptionNonce.kt @@ -29,10 +29,8 @@ class EncryptionNonce { companion object { const val TAG_NAME = "decryption-nonce" - @JvmStatic fun isTag(tag: Array) = tag.has(0) && tag[0] == TAG_NAME - @JvmStatic fun parse(tag: Array): ByteArray? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -40,7 +38,6 @@ class EncryptionNonce { return runCatching { tag[1].hexToByteArray() }.getOrNull() } - @JvmStatic fun assemble(nonce: ByteArray) = arrayOf(TAG_NAME, nonce.toHexKey()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/FileTypeTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/FileTypeTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/FileTypeTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/FileTypeTag.kt index d7a743a72b..2e8597f5ca 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/FileTypeTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/tags/FileTypeTag.kt @@ -32,7 +32,6 @@ class FileTypeTag { mimeTypes: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in mimeTypes - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -40,7 +39,6 @@ class FileTypeTag { return tag[1] } - @JvmStatic fun assemble(mimeType: String) = arrayOf(TAG_NAME, mimeType) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/messages/ChatMessageEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/messages/ChatMessageEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/messages/ChatMessageEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/messages/ChatMessageEvent.kt index 6293e094c5..b47f7c3b10 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/messages/ChatMessageEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/messages/ChatMessageEvent.kt @@ -27,6 +27,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag +import com.vitorpamplona.quartz.nip01Core.tags.people.toPTag import com.vitorpamplona.quartz.nip17Dm.base.BaseDMGroupEvent import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/messages/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/messages/TagArrayBuilderExt.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/messages/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/messages/TagArrayBuilderExt.kt index 6f50623dc0..d06d8699fb 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/messages/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/messages/TagArrayBuilderExt.kt @@ -26,6 +26,7 @@ import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTags import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag +import com.vitorpamplona.quartz.nip10Notes.tags.toMarkedETag import com.vitorpamplona.quartz.nip14Subject.SubjectTag import com.vitorpamplona.quartz.nip17Dm.base.BaseDMGroupEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/settings/ChatMessageRelayListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/settings/ChatMessageRelayListEvent.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/settings/ChatMessageRelayListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/settings/ChatMessageRelayListEvent.kt index 94dc26f079..6ed45ce92e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/settings/ChatMessageRelayListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/settings/ChatMessageRelayListEvent.kt @@ -21,13 +21,13 @@ package com.vitorpamplona.quartz.nip17Dm.settings import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip17Dm.settings.tags.RelayTag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/settings/tags/RelayTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/settings/tags/RelayTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/settings/tags/RelayTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/settings/tags/RelayTag.kt index b609c3509e..ebb7adf95d 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/settings/tags/RelayTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip17Dm/settings/tags/RelayTag.kt @@ -30,13 +30,10 @@ class RelayTag { companion object { const val TAG_NAME = "relay" - @JvmStatic fun match(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun notMatch(tag: Array) = !(tag.has(0) && tag[0] == TAG_NAME) - @JvmStatic fun parse(tag: Array): NormalizedRelayUrl? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -49,7 +46,6 @@ class RelayTag { return relay } - @JvmStatic fun assemble(relay: NormalizedRelayUrl) = arrayOf(TAG_NAME, relay.url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/GenericRepostEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/GenericRepostEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/GenericRepostEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/GenericRepostEvent.kt index acf7e2b1b0..9f465bfe7b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/GenericRepostEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/GenericRepostEvent.kt @@ -31,8 +31,8 @@ import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.aTag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.aTag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.events.eTag import com.vitorpamplona.quartz.nip01Core.tags.kinds.kind diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/RepostEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/RepostEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/RepostEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/RepostEvent.kt index c7feb946ba..0a7668949d 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/RepostEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/RepostEvent.kt @@ -30,8 +30,8 @@ import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.aTag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.aTag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.events.eTag import com.vitorpamplona.quartz.nip01Core.tags.kinds.kind diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/EntityExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/EntityExt.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/EntityExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/EntityExt.kt index 927eb0c872..687bae4923 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/EntityExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/EntityExt.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.quartz.nip18Reposts.quotes import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip19Bech32.entities.NAddress import com.vitorpamplona.quartz.nip19Bech32.entities.NEmbed diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QAddressableTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QAddressableTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QAddressableTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QAddressableTag.kt index db1b5eb148..a84e27981f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QAddressableTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QAddressableTag.kt @@ -21,11 +21,11 @@ package com.vitorpamplona.quartz.nip18Reposts.quotes import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.ensure @@ -63,7 +63,6 @@ data class QAddressableTag( companion object { const val TAG_NAME = "q" - @JvmStatic fun parse(tag: Array): QAddressableTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -73,7 +72,6 @@ data class QAddressableTag( return QAddressableTag(address, hint) } - @JvmStatic fun assemble( kind: Int, pubKeyHex: HexKey, @@ -81,7 +79,6 @@ data class QAddressableTag( relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, Address.assemble(kind, pubKeyHex, dTag), relay?.url) - @JvmStatic fun assemble( address: Address, relay: NormalizedRelayUrl?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QEventTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QEventTag.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QEventTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QEventTag.kt index aa8344b74d..3f088ec42e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QEventTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QEventTag.kt @@ -21,8 +21,10 @@ package com.vitorpamplona.quartz.nip18Reposts.quotes import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.has +import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.utils.arrayOfNotNull @@ -53,7 +55,6 @@ data class QEventTag( companion object { const val TAG_NAME = "q" - @JvmStatic fun parse(tag: Array): QEventTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -64,7 +65,6 @@ data class QEventTag( return QEventTag(tag[1], hint, tag.getOrNull(3)) } - @JvmStatic fun assemble( eventId: HexKey, relay: NormalizedRelayUrl?, @@ -72,3 +72,5 @@ data class QEventTag( ) = arrayOfNotNull(TAG_NAME, eventId, relay?.url, author) } } + +fun EventHintBundle.toQTagArray() = QEventTag.assemble(event.id, relay, event.pubKey) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QTag.kt index 14c74e3afe..90d5944b74 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/QTag.kt @@ -20,13 +20,13 @@ */ package com.vitorpamplona.quartz.nip18Reposts.quotes +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.utils.ensure interface QTag { @@ -35,7 +35,6 @@ interface QTag { companion object { const val TAG_NAME = "q" - @JvmStatic fun parse(tag: Array): QTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -62,14 +61,12 @@ interface QTag { return null } - @JvmStatic fun parseId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } return tag[1] } - @JvmStatic fun parseEventId(tag: Array): HexKey? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -77,7 +74,6 @@ interface QTag { return tag[1] } - @JvmStatic fun parseEventAsHint(tag: Array): EventIdHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -98,7 +94,6 @@ interface QTag { return tag[1] } - @JvmStatic fun parseAddressAsHint(tag: Array): AddressHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip18Reposts/quotes/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/ATagExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/ATagExt.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/ATagExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/ATagExt.kt index dc9bb9d641..8b127cc835 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/ATagExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/ATagExt.kt @@ -20,12 +20,12 @@ */ package com.vitorpamplona.quartz.nip19Bech32 -import android.util.Log import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip19Bech32.entities.NAddress import com.vitorpamplona.quartz.utils.Hex +import com.vitorpamplona.quartz.utils.Log fun ATag.Companion.isATag(key: String): Boolean = key.startsWith("naddr1") || key.contains(":") diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/ByteArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/ByteArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/ByteArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/ByteArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/EventExt.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/EventExt.kt index 8d96412d4a..8e377e44e8 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/EventExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/EventExt.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.quartz.nip19Bech32 import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent fun Event.toNIP19(relayHint: NormalizedRelayUrl? = null): String = diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/ListEntityExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/ListEntityExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/ListEntityExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/ListEntityExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/Nip19Parser.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/Nip19Parser.kt similarity index 80% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/Nip19Parser.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/Nip19Parser.kt index 8c53dab402..8751562e22 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/Nip19Parser.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/Nip19Parser.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.quartz.nip19Bech32 -import android.util.Log import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray @@ -37,26 +36,28 @@ import com.vitorpamplona.quartz.nip19Bech32.entities.NPub import com.vitorpamplona.quartz.nip19Bech32.entities.NRelay import com.vitorpamplona.quartz.nip19Bech32.entities.NSec import com.vitorpamplona.quartz.utils.Hex +import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException -import java.util.regex.Pattern +import kotlin.sequences.forEach +import kotlin.text.Regex object Nip19Parser { - private val nip19PlusNip46regex: Pattern = - Pattern.compile( + private val nip19PlusNip46regex: Regex = + Regex( "(nostr:)?@?((nsec1|npub1|note1)([qpzry9x8gf2tvdw0s3jn54khce6mua7l]{58})|(nevent1|naddr1|nprofile1|nrelay1|nembed1|ncryptsec1)([qpzry9x8gf2tvdw0s3jn54khce6mua7l]+))([\\S]*)", - Pattern.CASE_INSENSITIVE, + RegexOption.IGNORE_CASE, ) - val nip19regex: Pattern = - Pattern.compile( + val nip19regex: Regex = + Regex( "(nostr:)?@?((nsec1|npub1|note1)([qpzry9x8gf2tvdw0s3jn54khce6mua7l]{58})|(nevent1|naddr1|nprofile1|nrelay1|nembed1)([qpzry9x8gf2tvdw0s3jn54khce6mua7l]+))([\\S]*)", - Pattern.CASE_INSENSITIVE, + RegexOption.IGNORE_CASE, ) - val nip19regexEvents: Pattern = - Pattern.compile( + val nip19regexEvents: Regex = + Regex( "(nostr:)?@?(nevent1|naddr1|note1|nrelay1|nembed1)([qpzry9x8gf2tvdw0s3jn54khce6mua7l]+)([\\S]*)", - Pattern.CASE_INSENSITIVE, + RegexOption.IGNORE_CASE, ) @Immutable @@ -70,13 +71,13 @@ object Nip19Parser { if (uri == null) return null try { - val matcher = nip19PlusNip46regex.matcher(uri) - if (!matcher.find()) { + val matcher = nip19PlusNip46regex.find(uri) + if (matcher == null) { return null } - val type = matcher.group(3) ?: matcher.group(5) // npub1 - val key = matcher.group(4) ?: matcher.group(6) // bech32 + val type = matcher.groups[3]?.value ?: matcher.groups[5]?.value // npub1 + val key = matcher.groups[4]?.value ?: matcher.groups[6]?.value // bech32 return type!! + key } catch (e: Throwable) { @@ -90,18 +91,18 @@ object Nip19Parser { if (uri == null) return null try { - val matcher = nip19regex.matcher(uri) - if (!matcher.find()) { + val matcher = nip19PlusNip46regex.find(uri) + if (matcher == null) { return null } - val type = matcher.group(3) ?: matcher.group(5) // npub1 - val key = matcher.group(4) ?: matcher.group(6) // bech32 - val additionalChars = matcher.group(7) // additional chars + val type = matcher.groups[3]?.value ?: matcher.groups[5]?.value // npub1 + val key = matcher.groups[4]?.value ?: matcher.groups[6]?.value // bech32 + val additionalChars = matcher.groups[7]?.value // additional chars if (type == null) return null - return parseComponents(type, key, additionalChars.ifEmpty { null }) + return parseComponents(type, key, additionalChars?.ifEmpty { null }) } catch (e: Throwable) { Log.e("NIP19 Parser", "Issue trying to Decode NIP19 $uri: ${e.message}") } @@ -136,13 +137,15 @@ object Nip19Parser { null } + fun hasAny(content: String): Boolean = nip19regex.matches(content) + fun parseAll(content: String): List { - val matcher = nip19regex.matcher(content) + val matchSequence = nip19regex.findAll(content) val returningList = mutableListOf() - while (matcher.find()) { - val type = matcher.group(3) ?: matcher.group(5) // npub1 - val key = matcher.group(4) ?: matcher.group(6) // bech32 - val additionalChars = matcher.group(7) // additional chars + matchSequence.forEach { matcher -> + val type = matcher.groups[3]?.value ?: matcher.groups[5]?.value // npub1 + val key = matcher.groups[4]?.value ?: matcher.groups[6]?.value // bech32 + val additionalChars = matcher.groups[7]?.value // additional chars if (type != null) { val parsed = parseComponents(type, key, additionalChars)?.entity @@ -156,12 +159,12 @@ object Nip19Parser { } fun parseAllEvents(content: String): List { - val matcher2 = nip19regexEvents.matcher(content) + val matchSequence = nip19regexEvents.findAll(content) val returningList = mutableListOf() - while (matcher2.find()) { - val type = matcher2.group(2) // npub1 - val key = matcher2.group(3) // bech32 - val additionalChars = matcher2.group(4) // additional chars + matchSequence.forEach { matcher -> + val type = matcher.groups[2]?.value // npub1 + val key = matcher.groups[3]?.value // bech32 + val additionalChars = matcher.groups[4]?.value // additional chars if (type != null) { val parsed = parseComponents(type, key, additionalChars)?.entity diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvTypes.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvTypes.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvTypes.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvTypes.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/bech32/Bech32Util.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/bech32/Bech32Util.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/bech32/Bech32Util.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/bech32/Bech32Util.kt index 066b90dc1c..0383a2d9b7 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/bech32/Bech32Util.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/bech32/Bech32Util.kt @@ -123,7 +123,7 @@ object Bech32 { * @param encoding encoding to use (bech32 or bech32m) * @return hrp + data encoded as a Bech32 string */ - @JvmStatic + public fun encode( hrp: String, int5s: ArrayList, @@ -149,7 +149,7 @@ object Bech32 { * @param encoding encoding to use (bech32 or bech32m) * @return hrp + data encoded as a Bech32 string */ - @JvmStatic + public fun encodeBytes( hrp: String, data: ByteArray, @@ -163,7 +163,7 @@ object Bech32 { * @param noChecksum if true, the bech32 string doesn't have a checksum * @return a (hrp, data, encoding) tuple */ - @JvmStatic + public fun decode( bech32: String, noChecksum: Boolean = false, @@ -203,7 +203,7 @@ object Bech32 { * @param noChecksum if true, the bech32 string doesn't have a checksum * @return a (hrp, data, encoding) tuple */ - @JvmStatic + public fun decodeBytes( bech32: String, noChecksum: Boolean = false, @@ -239,7 +239,7 @@ object Bech32 { * @param input a sequence of 8 bits integers * @return a sequence of 5 bits integers */ - @JvmStatic + public fun eight2five(input: ByteArray): ArrayList { var buffer = 0L // larger array on purpose. Checksum is added later. @@ -261,7 +261,7 @@ object Bech32 { * @param input a sequence of 5 bits integers * @return a sequence of 8 bits integers */ - @JvmStatic + public fun five2eight( input: Array, offset: Int, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/Entity.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/Entity.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/Entity.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/Entity.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NAddress.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NAddress.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NAddress.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NAddress.kt index 3fe4138749..6c4812f8cf 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NAddress.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NAddress.kt @@ -24,16 +24,16 @@ import addHex import addInt import addString import addStringIfNotBlank -import android.util.Log import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip19Bech32.TlvTypes import com.vitorpamplona.quartz.nip19Bech32.bech32.bechToBytes import com.vitorpamplona.quartz.nip19Bech32.tlv.Tlv import com.vitorpamplona.quartz.nip19Bech32.tlv.TlvBuilder import com.vitorpamplona.quartz.nip19Bech32.toNAddress +import com.vitorpamplona.quartz.utils.Log @Immutable data class NAddress( diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NEmbed.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NEmbed.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NEmbed.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NEmbed.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NNote.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NNote.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NNote.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NNote.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NProfile.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NProfile.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NProfile.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NProfile.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NPub.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NPub.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NPub.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NPub.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NRelay.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NRelay.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NRelay.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NRelay.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NSec.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NSec.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NSec.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/entities/NSec.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/tlv/Tlv.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/tlv/Tlv.kt similarity index 77% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/tlv/Tlv.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/tlv/Tlv.kt index 046709b51b..4dfe4a2bed 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/tlv/Tlv.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/tlv/Tlv.kt @@ -21,25 +21,24 @@ package com.vitorpamplona.quartz.nip19Bech32.tlv import com.vitorpamplona.quartz.nip01Core.core.toHexKey -import java.nio.ByteBuffer -import java.nio.ByteOrder +import com.vitorpamplona.quartz.utils.internIfPossible class Tlv( val data: Map>, ) { fun asInt(type: Byte) = data[type]?.mapNotNull { it.toInt32() } - fun asHex(type: Byte) = data[type]?.map { it.toHexKey().intern() } + fun asHex(type: Byte) = data[type]?.map { it.toHexKey().internIfPossible() } - fun asString(type: Byte) = data[type]?.map { it.toString(Charsets.UTF_8) } + fun asString(type: Byte) = data[type]?.map { it.decodeToString() } fun firstAsInt(type: Byte) = data[type]?.firstOrNull()?.toInt32() - fun firstAsHex(type: Byte) = data[type]?.firstOrNull()?.toHexKey()?.intern() + fun firstAsHex(type: Byte) = data[type]?.firstOrNull()?.toHexKey()?.internIfPossible() - fun firstAsString(type: Byte) = data[type]?.firstOrNull()?.toString(Charsets.UTF_8) + fun firstAsString(type: Byte) = data[type]?.firstOrNull()?.decodeToString() - fun asStringList(type: Byte) = data[type]?.map { it.toString(Charsets.UTF_8) } + fun asStringList(type: Byte) = data[type]?.map { it.decodeToString() } companion object { fun parse(data: ByteArray): Tlv { @@ -64,5 +63,15 @@ class Tlv( fun ByteArray.toInt32(): Int? { if (size != 4) return null - return ByteBuffer.wrap(this, 0, 4).order(ByteOrder.BIG_ENDIAN).int + val result = + ((this[0].toLong() and 0xFF) shl 24) or + ((this[1].toLong() and 0xFF) shl 16) or + ((this[2].toLong() and 0xFF) shl 8) or + (this[3].toLong() and 0xFF) + + // check(result <= Int.MAX_VALUE) { + // "Max value to signed int $result" + // } + + return result.toInt() } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/tlv/TlvBuilder.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/tlv/TlvBuilder.kt similarity index 90% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/tlv/TlvBuilder.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/tlv/TlvBuilder.kt index b09881d57b..51a1ff97fe 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/tlv/TlvBuilder.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip19Bech32/tlv/TlvBuilder.kt @@ -22,23 +22,24 @@ package com.vitorpamplona.quartz.nip19Bech32.tlv import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray -import java.io.ByteArrayOutputStream +import com.vitorpamplona.quartz.utils.ByteArrayOutputStream class TlvBuilder { - val outputStream = ByteArrayOutputStream() + val outputStream = ByteArrayOutputStream(100) private fun add( type: Byte, byteArray: ByteArray, ) { - outputStream.write(byteArrayOf(type, byteArray.size.toByte())) + outputStream.write(type) + outputStream.write(byteArray.size.toByte()) outputStream.write(byteArray) } fun addString( type: Byte, string: String, - ) = add(type, string.toByteArray(Charsets.UTF_8)) + ) = add(type, string.encodeToByteArray()) fun addHex( type: Byte, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip21UriScheme/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip21UriScheme/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip21UriScheme/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip21UriScheme/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/CommentEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/CommentEvent.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/CommentEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/CommentEvent.kt index a525606915..6b3308f05d 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/CommentEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/CommentEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip22Comments import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey @@ -34,7 +35,6 @@ import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHashTag import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent import com.vitorpamplona.quartz.nip18Reposts.quotes.QTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/RootScope.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/RootScope.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/RootScope.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/RootScope.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyAddressTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyAddressTag.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyAddressTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyAddressTag.kt index 4035d3ce6f..5faf669b2a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyAddressTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyAddressTag.kt @@ -21,13 +21,13 @@ package com.vitorpamplona.quartz.nip22Comments.tags import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.Tag import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.ensure @@ -41,16 +41,13 @@ class ReplyAddressTag( companion object { const val TAG_NAME = "a" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun isTagged( tag: Array, addressId: String, ) = tag.has(1) && tag[0] == RootAddressTag.Companion.TAG_NAME && tag[1] == addressId - @JvmStatic fun parse(tag: Array): ReplyAddressTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -61,7 +58,6 @@ class ReplyAddressTag( return ReplyAddressTag(tag[1], relayHint) } - @JvmStatic fun parseAddress(tag: Array): Address? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -70,7 +66,6 @@ class ReplyAddressTag( return Address.parse(tag[1]) } - @JvmStatic fun parseAddressId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -78,7 +73,6 @@ class ReplyAddressTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): AddressHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -91,13 +85,11 @@ class ReplyAddressTag( return AddressHint(tag[1], relayHint) } - @JvmStatic fun assemble( addressId: HexKey, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, addressId, relay?.url) - @JvmStatic fun assemble( kind: Int, pubKey: String, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyAuthorTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyAuthorTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyAuthorTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyAuthorTag.kt index f006a731e1..5c752b7a3f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyAuthorTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyAuthorTag.kt @@ -41,10 +41,8 @@ data class ReplyAuthorTag( companion object { const val TAG_NAME = "p" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun parse(tag: Tag): ReplyAuthorTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -55,7 +53,6 @@ data class ReplyAuthorTag( return ReplyAuthorTag(tag[1], hint) } - @JvmStatic fun parseKey(tag: Tag): HexKey? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -63,7 +60,6 @@ data class ReplyAuthorTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): PubKeyHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -76,7 +72,6 @@ data class ReplyAuthorTag( return PubKeyHint(tag[1], hint) } - @JvmStatic fun assemble( pubkey: HexKey, relayHint: NormalizedRelayUrl?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyEventTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyEventTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyEventTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyEventTag.kt index 4f891256f2..9a17884178 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyEventTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyEventTag.kt @@ -43,22 +43,18 @@ class ReplyEventTag( companion object { const val TAG_NAME = "e" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun isTagged( tag: Array, eventId: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == eventId - @JvmStatic fun isIn( tag: Array, eventIds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in eventIds - @JvmStatic fun parse(tag: Array): ReplyEventTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -66,7 +62,6 @@ class ReplyEventTag( return ReplyEventTag(tag[1], tag.getOrNull(2)?.let { RelayUrlNormalizer.normalizeOrNull(it) }, tag.getOrNull(3)) } - @JvmStatic fun parseKey(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -74,7 +69,6 @@ class ReplyEventTag( return tag[1] } - @JvmStatic fun parseValidKey(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -83,7 +77,6 @@ class ReplyEventTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): EventIdHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -96,14 +89,12 @@ class ReplyEventTag( return EventIdHint(tag[1], relayHint) } - @JvmStatic fun assemble( eventId: HexKey, relay: NormalizedRelayUrl?, pubkey: String?, ) = arrayOfNotNull(TAG_NAME, eventId, relay?.url, pubkey) - @JvmStatic fun assemble(ref: EventReference) = assemble(ref.eventId, ref.relayHint, ref.author) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyIdentifierTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyIdentifierTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyIdentifierTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyIdentifierTag.kt index a3c9a23edf..284fd36d96 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyIdentifierTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyIdentifierTag.kt @@ -42,10 +42,8 @@ class ReplyIdentifierTag { companion object { const val TAG_NAME = "i" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun isTagged( tag: Array, encodedScope: String, @@ -82,7 +80,6 @@ class ReplyIdentifierTag { match: (String, Set) -> Boolean, ) = tag.has(1) && tag[0] == TAG_NAME && match(tag[1], value) - @JvmStatic fun parse(tag: Tag): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -90,7 +87,6 @@ class ReplyIdentifierTag { return tag[1] } - @JvmStatic fun parseExternalId(tag: Tag): ExternalId? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -110,13 +106,11 @@ class ReplyIdentifierTag { ?: UrlId.parse(value, hint) } - @JvmStatic fun assemble( identity: String, hint: String?, ) = arrayOfNotNull(TAG_NAME, identity, hint) - @JvmStatic fun assemble(id: ExternalId): Array = assemble(id.toScope(), id.hint()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyKindTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyKindTag.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyKindTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyKindTag.kt index 7a19f9aa86..502fac5164 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyKindTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/ReplyKindTag.kt @@ -29,28 +29,23 @@ class ReplyKindTag { companion object { const val TAG_NAME = "k" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun isKind( tag: Tag, kind: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == kind - @JvmStatic fun isTagged( tag: Tag, kind: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == kind - @JvmStatic fun isIn( tag: Tag, kinds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in kinds - @JvmStatic fun parse(tag: Tag): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -58,19 +53,14 @@ class ReplyKindTag { return tag[1] } - @JvmStatic fun assemble(kind: String) = arrayOf(TAG_NAME, kind) - @JvmStatic fun assemble(kind: Int) = arrayOf(TAG_NAME, kind.toString()) - @JvmStatic fun assemble(id: ExternalId) = assemble(id.toKind()) - @JvmStatic fun assemble(kinds: List): List = kinds.map { assemble(it) } - @JvmStatic fun assemble(kinds: Set): List = kinds.map { assemble(it) } } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootAddressTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootAddressTag.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootAddressTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootAddressTag.kt index 04688cb9eb..616de27093 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootAddressTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootAddressTag.kt @@ -21,13 +21,13 @@ package com.vitorpamplona.quartz.nip22Comments.tags import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.Tag import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.ensure @@ -41,22 +41,18 @@ class RootAddressTag( companion object { const val TAG_NAME = "A" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun isTagged( tag: Array, addressId: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == addressId - @JvmStatic fun isIn( tag: Array, addressIds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in addressIds - @JvmStatic fun parse(tag: Array): RootAddressTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -67,7 +63,6 @@ class RootAddressTag( return RootAddressTag(tag[1], relayHint) } - @JvmStatic fun parseAddress(tag: Array): Address? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -76,7 +71,6 @@ class RootAddressTag( return Address.parse(tag[1]) } - @JvmStatic fun parseValidAddress(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -84,7 +78,6 @@ class RootAddressTag( return Address.parse(tag[1])?.toValue() } - @JvmStatic fun parseAddressId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -92,7 +85,6 @@ class RootAddressTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): AddressHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -105,13 +97,11 @@ class RootAddressTag( return AddressHint(tag[1], relayHint) } - @JvmStatic fun assemble( addressId: HexKey, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, addressId, relay?.url) - @JvmStatic fun assemble( kind: Int, pubKey: String, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootAuthorTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootAuthorTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootAuthorTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootAuthorTag.kt index a4afdeda8b..a63df910e5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootAuthorTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootAuthorTag.kt @@ -42,10 +42,8 @@ data class RootAuthorTag( companion object { const val TAG_NAME = "P" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun parse(tag: Tag): ReplyAuthorTag? { if (tag.size < 2 || tag[0] != TAG_NAME || tag[1].length != PUBKEY_LENGTH) return null @@ -54,7 +52,6 @@ data class RootAuthorTag( return ReplyAuthorTag(tag[1], relayHint) } - @JvmStatic fun parse3(tag: Tag): ReplyAuthorTag? { ensure(tag.size >= 2) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -65,13 +62,11 @@ data class RootAuthorTag( return ReplyAuthorTag(tag[1], relayHint) } - @JvmStatic fun parseKey(tag: Tag): HexKey? { if (tag.size < 2 || tag[0] != TAG_NAME || tag[1].length != PUBKEY_LENGTH) return null return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): PubKeyHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -84,7 +79,6 @@ data class RootAuthorTag( return PubKeyHint(tag[1], relayHint) } - @JvmStatic fun assemble( pubkey: HexKey, relayHint: NormalizedRelayUrl?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootEventTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootEventTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootEventTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootEventTag.kt index ce210e6e8a..1a5d6ad1af 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootEventTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootEventTag.kt @@ -43,22 +43,18 @@ class RootEventTag( companion object { const val TAG_NAME = "E" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun isTagged( tag: Array, eventId: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == eventId - @JvmStatic fun isIn( tag: Array, eventIds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in eventIds - @JvmStatic fun parse(tag: Array): RootEventTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -69,7 +65,6 @@ class RootEventTag( return RootEventTag(tag[1], relayHint, tag.getOrNull(3)) } - @JvmStatic fun parseKey(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -77,7 +72,6 @@ class RootEventTag( return tag[1] } - @JvmStatic fun parseValidKey(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -86,7 +80,6 @@ class RootEventTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): EventIdHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -99,14 +92,12 @@ class RootEventTag( return EventIdHint(tag[1], relayHint) } - @JvmStatic fun assemble( eventId: HexKey, relay: NormalizedRelayUrl?, pubkey: String?, ) = arrayOfNotNull(TAG_NAME, eventId, relay?.url, pubkey) - @JvmStatic fun assemble(ref: EventReference) = assemble(ref.eventId, ref.relayHint, ref.author) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootIdentifierTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootIdentifierTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootIdentifierTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootIdentifierTag.kt index db5d43c61a..07af343345 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootIdentifierTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootIdentifierTag.kt @@ -42,7 +42,6 @@ class RootIdentifierTag { companion object { const val TAG_NAME = "I" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() fun isTagged( @@ -81,7 +80,6 @@ class RootIdentifierTag { match: (String, Set) -> Boolean, ) = tag.has(1) && tag[0] == TAG_NAME && match(tag[1], value) - @JvmStatic fun parse(tag: Tag): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -89,7 +87,6 @@ class RootIdentifierTag { return tag[1] } - @JvmStatic fun parseExternalId(tag: Tag): ExternalId? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -109,13 +106,11 @@ class RootIdentifierTag { ?: UrlId.parse(value, hint) } - @JvmStatic fun assemble( identity: String, hint: String?, ) = arrayOfNotNull(TAG_NAME, identity, hint) - @JvmStatic fun assemble(id: ExternalId): Array = assemble(id.toScope(), id.hint()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootKindTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootKindTag.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootKindTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootKindTag.kt index a295a4da71..b8981699e2 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootKindTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip22Comments/tags/RootKindTag.kt @@ -29,16 +29,13 @@ class RootKindTag { companion object { const val TAG_NAME = "K" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun isKind( tag: Tag, kind: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == kind - @JvmStatic fun parse(tag: Tag): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -46,19 +43,14 @@ class RootKindTag { return tag[1] } - @JvmStatic fun assemble(kind: String): Tag = arrayOf(TAG_NAME, kind) - @JvmStatic fun assemble(kind: Int): Tag = assemble(kind.toString()) - @JvmStatic fun assemble(id: ExternalId) = assemble(id.toKind()) - @JvmStatic fun assemble(kinds: List): List = kinds.map { assemble(it) } - @JvmStatic fun assemble(kinds: Set): List = kinds.map { assemble(it) } } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt index 809e39c2d7..6160c16700 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/LongTextNoteEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip23LongContent import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder @@ -32,9 +33,8 @@ import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.publishedAt.PublishedAtProvider @@ -54,7 +54,8 @@ import com.vitorpamplona.quartz.nip23LongContent.tags.TitleTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip50Search.SearchableEvent import com.vitorpamplona.quartz.utils.TimeUtils -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable class LongTextNoteEvent( @@ -148,13 +149,14 @@ class LongTextNoteEvent( companion object { const val KIND = 30023 + @OptIn(ExperimentalUuidApi::class) fun build( description: String, title: String, summary: String? = null, image: String? = null, publishedAt: Long? = null, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = eventTemplate(KIND, description, createdAt) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/ImageTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/ImageTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/ImageTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/ImageTag.kt index efe83c17a5..983a998f0d 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/ImageTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/ImageTag.kt @@ -27,7 +27,6 @@ class ImageTag { companion object { const val TAG_NAME = "image" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class ImageTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/PublishedAtTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/PublishedAtTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/PublishedAtTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/PublishedAtTag.kt index 3b78184731..2cf188b019 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/PublishedAtTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/PublishedAtTag.kt @@ -27,7 +27,6 @@ class PublishedAtTag { companion object { const val TAG_NAME = "published_at" - @JvmStatic fun parse(tag: Array): Long? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -44,7 +43,6 @@ class PublishedAtTag { } } - @JvmStatic fun assemble(timestamp: Long) = arrayOf(TAG_NAME, timestamp.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/SummaryTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/SummaryTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/SummaryTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/SummaryTag.kt index 4ea010ab34..2c4fdf86b5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/SummaryTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/SummaryTag.kt @@ -27,7 +27,6 @@ class SummaryTag { companion object { const val TAG_NAME = "summary" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class SummaryTag { return tag[1] } - @JvmStatic fun assemble(title: String) = arrayOf(TAG_NAME, title) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/TitleTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/TitleTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/TitleTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/TitleTag.kt index b49e0e9a52..c51d90b8a6 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/TitleTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip23LongContent/tags/TitleTag.kt @@ -27,7 +27,6 @@ class TitleTag { companion object { const val TAG_NAME = "title" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class TitleTag { return tag[1] } - @JvmStatic fun assemble(title: String) = arrayOf(TAG_NAME, title) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip25Reactions/ReactionEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip25Reactions/ReactionEvent.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip25Reactions/ReactionEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip25Reactions/ReactionEvent.kt index 3c11b0d017..d5e43edfa1 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip25Reactions/ReactionEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip25Reactions/ReactionEvent.kt @@ -29,10 +29,11 @@ import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.aTag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.aTag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.events.eTag +import com.vitorpamplona.quartz.nip01Core.tags.events.toETag import com.vitorpamplona.quartz.nip01Core.tags.kinds.kind import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelCreateEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelCreateEvent.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelCreateEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelCreateEvent.kt index e5ad9f3407..779b6439ef 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelCreateEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelCreateEvent.kt @@ -20,10 +20,7 @@ */ package com.vitorpamplona.quartz.nip28PublicChat.admin -import android.util.Log import androidx.compose.runtime.Immutable -import com.fasterxml.jackson.core.JsonParseException -import com.fasterxml.jackson.databind.exc.MismatchedInputException import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder @@ -35,7 +32,9 @@ import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip28PublicChat.base.ChannelData import com.vitorpamplona.quartz.nip28PublicChat.base.ChannelDataNorm import com.vitorpamplona.quartz.nip31Alts.alt +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils +import kotlinx.coroutines.CancellationException @Immutable class ChannelCreateEvent( @@ -47,7 +46,8 @@ class ChannelCreateEvent( sig: HexKey, ) : Event(id, pubKey, createdAt, KIND, tags, content, sig), EventHintProvider { - @Transient + @kotlinx.serialization.Transient + @kotlin.jvm.Transient var cache: ChannelDataNorm? = null override fun eventHints() = channelInfo().relays?.map { EventIdHint(id, it) } ?: emptyList() @@ -66,10 +66,8 @@ class ChannelCreateEvent( } else { ChannelData.parse(content)?.normalize() ?: ChannelDataNorm() } - } catch (e: JsonParseException) { - Log.w("ChannelCreateEvent", "Failure to parse ${this.toJson()}", e) - ChannelDataNorm() - } catch (e: MismatchedInputException) { + } catch (e: Exception) { + if (e is CancellationException) throw e Log.w("ChannelCreateEvent", "Failure to parse ${this.toJson()}", e) ChannelDataNorm() } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelHideMessageEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelHideMessageEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelHideMessageEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelHideMessageEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelMetadataEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelMetadataEvent.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelMetadataEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelMetadataEvent.kt index eabbdb7542..9f87a62988 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelMetadataEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelMetadataEvent.kt @@ -20,9 +20,7 @@ */ package com.vitorpamplona.quartz.nip28PublicChat.admin -import android.util.Log import androidx.compose.runtime.Immutable -import com.fasterxml.jackson.core.JsonParseException import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.core.has @@ -37,7 +35,9 @@ import com.vitorpamplona.quartz.nip28PublicChat.base.ChannelData import com.vitorpamplona.quartz.nip28PublicChat.base.ChannelDataNorm import com.vitorpamplona.quartz.nip28PublicChat.base.channel import com.vitorpamplona.quartz.nip31Alts.alt +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils +import kotlinx.coroutines.CancellationException @Immutable class ChannelMetadataEvent( @@ -49,7 +49,8 @@ class ChannelMetadataEvent( sig: HexKey, ) : BasePublicChatEvent(id, pubKey, createdAt, KIND, tags, content, sig), EventHintProvider { - @Transient + @kotlinx.serialization.Transient + @kotlin.jvm.Transient var cache: ChannelDataNorm? = null override fun eventHints() = @@ -69,9 +70,10 @@ class ChannelMetadataEvent( if (content.isEmpty() || !content.startsWith("{") || isEncrypted()) { ChannelDataNorm() } else { - ChannelData.parse(content)?.normalize() ?: ChannelDataNorm() + ChannelData.parse(content).normalize() ?: ChannelDataNorm() } - } catch (e: JsonParseException) { + } catch (e: Exception) { + if (e is CancellationException) throw e Log.w("ChannelCreateEvent", "Failure to parse ${this.toJson()}", e) ChannelDataNorm() } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelMuteUserEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelMuteUserEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelMuteUserEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/admin/ChannelMuteUserEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/BasePublicChatEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/BasePublicChatEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/BasePublicChatEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/BasePublicChatEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/ChannelData.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/ChannelData.kt similarity index 86% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/ChannelData.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/ChannelData.kt index b93684d5cc..94963a656d 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/ChannelData.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/ChannelData.kt @@ -21,12 +21,13 @@ package com.vitorpamplona.quartz.nip28PublicChat.base import androidx.compose.runtime.Immutable -import com.fasterxml.jackson.module.kotlin.readValue -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer +import kotlinx.serialization.Serializable @Immutable +@Serializable data class ChannelData( val name: String? = null, val about: String? = null, @@ -38,9 +39,9 @@ data class ChannelData( fun normalize() = ChannelDataNorm(name, about, picture, relays?.mapNotNull { RelayUrlNormalizer.normalizeOrNull(it) }) companion object { - fun parse(content: String): ChannelData? = JsonMapper.mapper.readValue(content) + fun parse(content: String): ChannelData = JsonMapper.fromJson(content) - fun assemble(data: ChannelData) = JsonMapper.mapper.writeValueAsString(data) + fun assemble(data: ChannelData) = JsonMapper.toJson(data) } } @@ -50,7 +51,7 @@ data class ChannelDataNorm( val picture: String? = null, val relays: List? = null, ) { - fun denormalize() = ChannelData(name, about, picture, relays?.mapNotNull { it.url }) + fun denormalize() = ChannelData(name, about, picture, relays?.map { it.url }) fun toContent() = denormalize().toContent() } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/IsInPublicChatChannel.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/IsInPublicChatChannel.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/IsInPublicChatChannel.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/IsInPublicChatChannel.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/TagArrayBuilderExt.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/TagArrayBuilderExt.kt index 10f9474bf4..7c8778f1c1 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/base/TagArrayBuilderExt.kt @@ -27,6 +27,7 @@ import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTags import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag +import com.vitorpamplona.quartz.nip10Notes.tags.toMarkedETag import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/ChannelListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/ChannelListEvent.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/ChannelListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/ChannelListEvent.kt index 78773ba541..6fc027ac36 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/ChannelListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/ChannelListEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip28PublicChat.list import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder @@ -30,7 +31,6 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip28PublicChat.list.tags.ChannelTag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/tags/ChannelTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/tags/ChannelTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/tags/ChannelTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/tags/ChannelTag.kt index 122a9d7b0b..c2d3869724 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/tags/ChannelTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/list/tags/ChannelTag.kt @@ -53,16 +53,13 @@ class ChannelTag( companion object { const val TAG_NAME = "e" - @JvmStatic fun isTagged(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].length == 64 - @JvmStatic fun isTagged( tag: Array, eventId: HexKey, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == eventId - @JvmStatic fun parse(tag: Array): ChannelTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -71,7 +68,6 @@ class ChannelTag( return ChannelTag(tag[1], pickRelayHint(tag), pickAuthor(tag)) } - @JvmStatic fun parseId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -79,7 +75,6 @@ class ChannelTag( return tag[1] } - @JvmStatic private fun pickRelayHint(tag: Array): NormalizedRelayUrl? { if (tag.has(2) && tag[2].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[2])) return RelayUrlNormalizer.normalizeOrNull(tag[2]) if (tag.has(3) && tag[3].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[3])) return RelayUrlNormalizer.normalizeOrNull(tag[3]) @@ -87,7 +82,6 @@ class ChannelTag( return null } - @JvmStatic private fun pickAuthor(tag: Array): HexKey? { if (tag.has(2) && tag[2].length == 64) return tag[2] if (tag.has(3) && tag[3].length == 64) return tag[3] @@ -95,7 +89,6 @@ class ChannelTag( return null } - @JvmStatic fun parseAsHint(tag: Array): EventIdHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -109,7 +102,6 @@ class ChannelTag( return EventIdHint(tag[1], hint) } - @JvmStatic fun assemble( eventId: HexKey, relay: NormalizedRelayUrl?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/message/ChannelMessageEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/message/ChannelMessageEvent.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/message/ChannelMessageEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/message/ChannelMessageEvent.kt index 97a0440ba6..13cb860a09 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/message/ChannelMessageEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip28PublicChat/message/ChannelMessageEvent.kt @@ -32,7 +32,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/CustomEmoji.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/CustomEmoji.kt similarity index 83% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/CustomEmoji.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/CustomEmoji.kt index 4575d0a99a..b7d6a1b146 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/CustomEmoji.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/CustomEmoji.kt @@ -21,15 +21,14 @@ package com.vitorpamplona.quartz.nip30CustomEmoji import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList -import java.util.regex.Pattern class CustomEmoji { companion object { - val customEmojiPattern: Pattern = - Pattern.compile("\\:([A-Za-z0-9_\\-]+)\\:", Pattern.CASE_INSENSITIVE) + val customEmojiPattern: Regex = + Regex("\\:([A-Za-z0-9_\\-]+)\\:", RegexOption.IGNORE_CASE) fun fastMightContainEmoji( input: String, @@ -51,21 +50,19 @@ class CustomEmoji { fun createEmojiMap(tags: ImmutableListOfLists): Map = tags.lists.filter { it.size > 2 && it[0] == EmojiUrlTag.TAG_NAME }.associate { ":${it[1]}:" to it[2] } fun findAllEmojis(input: String): List { - val matcher = customEmojiPattern.matcher(input) - val emojiNamesInOrder = mutableListOf() - while (matcher.find()) { - emojiNamesInOrder.add(matcher.group()) - } - return emojiNamesInOrder + val matcher = customEmojiPattern.findAll(input) + return matcher + .mapNotNull { + it.groups[0]?.value + }.toList() } fun findAllEmojiCodes(input: String): List { - val matcher = customEmojiPattern.matcher(input) - val emojiNamesInOrder = mutableListOf() - while (matcher.find()) { - matcher.group(1)?.let { emojiNamesInOrder.add(it) } - } - return emojiNamesInOrder + val matcher = customEmojiPattern.findAll(input) + return matcher + .mapNotNull { + it.groups[1]?.value + }.toList() } fun assembleAnnotatedList( @@ -88,7 +85,7 @@ class CustomEmoji { return null } - val regularCharsInOrder = input.split(customEmojiPattern.toRegex()) + val regularCharsInOrder = input.split(customEmojiPattern) val finalList = mutableListOf() diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/EmojiUrlTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/EmojiUrlTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/EmojiUrlTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/EmojiUrlTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/pack/EmojiPackEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/pack/EmojiPackEvent.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/pack/EmojiPackEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/pack/EmojiPackEvent.kt index 4e7f4d0459..38355a8679 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/pack/EmojiPackEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/pack/EmojiPackEvent.kt @@ -24,13 +24,14 @@ import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent import com.vitorpamplona.quartz.nip34Git.repository.name import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent import com.vitorpamplona.quartz.utils.TimeUtils -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable class EmojiPackEvent( @@ -45,9 +46,10 @@ class EmojiPackEvent( const val KIND = 30030 const val ALT_DESCRIPTION = "Emoji pack" + @OptIn(ExperimentalUuidApi::class) fun build( name: String, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = eventTemplate(KIND, "", createdAt) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/EmojiPackSelectionEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/EmojiPackSelectionEvent.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/EmojiPackSelectionEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/EmojiPackSelectionEvent.kt index e4073aa414..8617244423 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/EmojiPackSelectionEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/EmojiPackSelectionEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip30CustomEmoji.selection import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder @@ -28,8 +29,8 @@ import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip01Core.signers.eventUpdate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.toATag import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/TagArrayBuilderExt.kt similarity index 84% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/TagArrayBuilderExt.kt index 208cf77530..1ea4f01433 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/selection/TagArrayBuilderExt.kt @@ -21,10 +21,10 @@ package com.vitorpamplona.quartz.nip30CustomEmoji.selection import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.aTag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.aTags -import com.vitorpamplona.quartz.nip01Core.tags.addressables.removeATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.aTag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.aTags +import com.vitorpamplona.quartz.nip01Core.tags.aTag.removeATag fun TagArrayBuilder.pack(tag: ATag) = aTag(tag) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip31Alts/AltTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip31Alts/AltTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip31Alts/AltTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip31Alts/AltTag.kt index 910c5a1793..3e706948f7 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip31Alts/AltTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip31Alts/AltTag.kt @@ -27,10 +27,8 @@ class AltTag { companion object { const val TAG_NAME = "alt" - @JvmStatic fun match(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -38,7 +36,6 @@ class AltTag { return tag[1] } - @JvmStatic fun assemble(altDescriptor: String) = arrayOf(TAG_NAME, altDescriptor) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip31Alts/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip31Alts/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip31Alts/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip31Alts/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip31Alts/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip31Alts/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip31Alts/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip31Alts/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip31Alts/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip31Alts/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip31Alts/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip31Alts/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/issue/GitIssueEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/issue/GitIssueEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/issue/GitIssueEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/issue/GitIssueEvent.kt index 3e99eea631..8a57ebee22 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/issue/GitIssueEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/issue/GitIssueEvent.kt @@ -31,7 +31,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/issue/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/issue/TagArrayBuilderExt.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/issue/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/issue/TagArrayBuilderExt.kt index 3371f51690..7a2ee256ae 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/issue/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/issue/TagArrayBuilderExt.kt @@ -22,7 +22,8 @@ package com.vitorpamplona.quartz.nip34Git.issue import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.toATag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTags import com.vitorpamplona.quartz.nip14Subject.SubjectTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/patch/GitPatchEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/patch/GitPatchEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/patch/GitPatchEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/patch/GitPatchEvent.kt index ab12e8be3d..d6b3e993ee 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/patch/GitPatchEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/patch/GitPatchEvent.kt @@ -21,14 +21,14 @@ package com.vitorpamplona.quartz.nip34Git.patch import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag import com.vitorpamplona.quartz.nip31Alts.AltTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/reply/GitReplyEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/reply/GitReplyEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/reply/GitReplyEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/reply/GitReplyEvent.kt index f6483a6730..9b0744c0b4 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/reply/GitReplyEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/reply/GitReplyEvent.kt @@ -31,7 +31,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/reply/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/reply/TagArrayBuilderExt.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/reply/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/reply/TagArrayBuilderExt.kt index a837fc98b0..66c9e77c83 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/reply/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/reply/TagArrayBuilderExt.kt @@ -22,10 +22,12 @@ package com.vitorpamplona.quartz.nip34Git.reply import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.toATag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTags import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag +import com.vitorpamplona.quartz.nip10Notes.tags.toMarkedETag import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent import com.vitorpamplona.quartz.nip34Git.patch.GitPatchEvent import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/GitRepositoryEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/GitRepositoryEvent.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/GitRepositoryEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/GitRepositoryEvent.kt index 6b761c5142..be2799384c 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/GitRepositoryEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/GitRepositoryEvent.kt @@ -25,14 +25,15 @@ import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip34Git.repository.tags.CloneTag import com.vitorpamplona.quartz.nip34Git.repository.tags.DescriptionTag import com.vitorpamplona.quartz.nip34Git.repository.tags.NameTag import com.vitorpamplona.quartz.nip34Git.repository.tags.WebTag import com.vitorpamplona.quartz.utils.TimeUtils -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable class GitRepositoryEvent( @@ -55,12 +56,13 @@ class GitRepositoryEvent( const val KIND = 30617 const val ALT_DESCRIPTION = "Git Repository" + @OptIn(ExperimentalUuidApi::class) fun build( name: String, description: String? = null, webUrl: String? = null, cloneUrl: String? = null, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = eventTemplate(KIND, "", createdAt) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/CloneTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/CloneTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/CloneTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/CloneTag.kt index 7cc77bacc9..3fb8d3e3cf 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/CloneTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/CloneTag.kt @@ -27,7 +27,6 @@ class CloneTag { companion object { const val TAG_NAME = "clone" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class CloneTag { return tag[1] } - @JvmStatic fun assemble(name: String) = arrayOf(TAG_NAME, name) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/DescriptionTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/DescriptionTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/DescriptionTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/DescriptionTag.kt index b065154d4a..abf1af670c 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/DescriptionTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/DescriptionTag.kt @@ -27,7 +27,6 @@ class DescriptionTag { companion object { const val TAG_NAME = "description" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class DescriptionTag { return tag[1] } - @JvmStatic fun assemble(name: String) = arrayOf(TAG_NAME, name) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/NameTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/NameTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/NameTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/NameTag.kt index 17296cc6d8..1d9c427e3e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/NameTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/NameTag.kt @@ -27,7 +27,6 @@ class NameTag { companion object { const val TAG_NAME = "name" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class NameTag { return tag[1] } - @JvmStatic fun assemble(name: String) = arrayOf(TAG_NAME, name) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/WebTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/WebTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/WebTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/WebTag.kt index 9476d37a83..324ec0d3ee 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/WebTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip34Git/repository/tags/WebTag.kt @@ -27,7 +27,6 @@ class WebTag { companion object { const val TAG_NAME = "web" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class WebTag { return tag[1] } - @JvmStatic fun assemble(name: String) = arrayOf(TAG_NAME, name) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/DefaultTrackers.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/DefaultTrackers.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/DefaultTrackers.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/DefaultTrackers.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TorrentCommentEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TorrentCommentEvent.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TorrentCommentEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TorrentCommentEvent.kt index 483a49a8d6..1c0c65fe2e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TorrentCommentEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TorrentCommentEvent.kt @@ -35,6 +35,7 @@ import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.events.eTags import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents +import com.vitorpamplona.quartz.nip01Core.tags.events.toETag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TorrentEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TorrentEvent.kt similarity index 85% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TorrentEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TorrentEvent.kt index 5bc95dc4bd..9a208bd9b8 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TorrentEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/TorrentEvent.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.quartz.nip35Torrents -import android.net.Uri import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey @@ -40,6 +39,7 @@ import com.vitorpamplona.quartz.nip35Torrents.tags.InfoHashTag import com.vitorpamplona.quartz.nip35Torrents.tags.TrackerTag import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarning import com.vitorpamplona.quartz.utils.TimeUtils +import com.vitorpamplona.quartz.utils.UrlEncoder @Immutable class TorrentEvent( @@ -60,18 +60,27 @@ class TorrentEvent( fun files() = tags.mapNotNull(FileTag::parse) - fun toMagnetLink(): String { - val builder = Uri.Builder() - builder - .scheme("magnet") - .appendQueryParameter("xt", "urn:btih:${btih()}") - .appendQueryParameter("dn", title()) + fun toMagnetLink(): String? { + val btih = btih()?.ifBlank { null } ?: return null + val title = title()?.ifBlank { null } - trackers().ifEmpty { DEFAULT_TRACKERS }.forEach { - builder.appendQueryParameter("tr", it) + return buildString { + append("magnet:?xt=urn:btih:") + append(btih) + append("&") + if (title != null) { + append("dn=") + append(UrlEncoder.encode(title)) + append("&") + } + trackers().forEachIndexed { idx, trackerUrl -> + if (idx > 0) { + append("&") + } + append("tr=") + append(UrlEncoder.encode(trackerUrl)) + } } - - return builder.build().toString() } fun totalSizeBytes(): Long = tags.sumOf { FileTag.parseBytes(it) ?: 0L } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/BtihTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/BtihTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/BtihTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/BtihTag.kt index cda984041f..3c3382687a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/BtihTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/BtihTag.kt @@ -27,7 +27,6 @@ class BtihTag { companion object { const val TAG_NAME = "btih" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class BtihTag { return tag[1] } - @JvmStatic fun assemble(btih: String) = arrayOf(TAG_NAME, btih) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/FileTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/FileTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/FileTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/FileTag.kt index f313ee2ca7..c6a06ea7bf 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/FileTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/FileTag.kt @@ -35,7 +35,6 @@ class FileTag( companion object { const val TAG_NAME = "file" - @JvmStatic fun parse(tag: Array): FileTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -43,7 +42,6 @@ class FileTag( return FileTag(tag[1], tag.getOrNull(2)?.toLongOrNull()) } - @JvmStatic fun parseBytes(tag: Array): Long? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -51,7 +49,6 @@ class FileTag( return tag[2].toLongOrNull() } - @JvmStatic fun assemble( name: String, bytes: Long?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/InfoHashTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/InfoHashTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/InfoHashTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/InfoHashTag.kt index 660a792258..4231642a6b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/InfoHashTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/InfoHashTag.kt @@ -27,7 +27,6 @@ class InfoHashTag { companion object { const val TAG_NAME = "x" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class InfoHashTag { return tag[1] } - @JvmStatic fun assemble(hash: String) = arrayOf(TAG_NAME, hash) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/TrackerTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/TrackerTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/TrackerTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/TrackerTag.kt index c482ec469c..467ed3f7e7 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/TrackerTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip35Torrents/tags/TrackerTag.kt @@ -27,7 +27,6 @@ class TrackerTag { companion object { const val TAG_NAME = "tracker" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class TrackerTag { return tag[1] } - @JvmStatic fun assemble(uri: String) = arrayOf(TAG_NAME, uri) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/ContentWarningTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/ContentWarningTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/ContentWarningTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/ContentWarningTag.kt index 47c1a15c6e..e5f6078d66 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/ContentWarningTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/ContentWarningTag.kt @@ -31,19 +31,15 @@ class ContentWarningTag( companion object { const val TAG_NAME = "content-warning" - @JvmStatic fun isTag(tag: Array) = tag.has(0) && tag[0] == TAG_NAME - @JvmStatic fun parse(tags: Array): ContentWarningTag { require(tags[0] == TAG_NAME) return ContentWarningTag(tags.getOrNull(1)) } - @JvmStatic fun assemble() = arrayOfNotNull(TAG_NAME) - @JvmStatic fun assemble(reason: String?) = arrayOfNotNull(TAG_NAME, reason) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip36SensitiveContent/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/DraftWrapCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/DraftWrapCache.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/DraftWrapCache.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/DraftWrapCache.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/DraftWrapEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/DraftWrapEvent.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/DraftWrapEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/DraftWrapEvent.kt index 7d3966bb9e..4da284b205 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/DraftWrapEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/DraftWrapEvent.kt @@ -20,9 +20,8 @@ */ package com.vitorpamplona.quartz.nip37Drafts -import android.util.Log import androidx.compose.runtime.Immutable -import com.fasterxml.jackson.core.JsonParseException +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey @@ -30,12 +29,13 @@ import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip01Core.tags.kinds.kind import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip40Expiration.expiration +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils +import kotlinx.coroutines.CancellationException @Immutable class DraftWrapEvent( @@ -58,7 +58,8 @@ class DraftWrapEvent( val json = signer.nip44Decrypt(content, pubKey) return try { fromJson(json) - } catch (e: JsonParseException) { + } catch (e: Exception) { + if (e is CancellationException) throw e Log.w("DraftEvent", "Unable to parse inner event of a draft: $json") throw e } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/ExposeInDraft.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/ExposeInDraft.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/ExposeInDraft.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/ExposeInDraft.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/privateOutbox/PrivateOutboxRelayListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/privateOutbox/PrivateOutboxRelayListEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/privateOutbox/PrivateOutboxRelayListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/privateOutbox/PrivateOutboxRelayListEvent.kt index 24889ffb0d..b3fff1a714 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/privateOutbox/PrivateOutboxRelayListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip37Drafts/privateOutbox/PrivateOutboxRelayListEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip37Drafts.privateOutbox import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @@ -28,8 +29,7 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip38UserStatus/StatusEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip38UserStatus/StatusEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip38UserStatus/StatusEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip38UserStatus/StatusEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/GitHubIdentity.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/GitHubIdentity.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/GitHubIdentity.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/GitHubIdentity.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/IdentityClaimTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/IdentityClaimTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/IdentityClaimTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/IdentityClaimTag.kt index 407bc37102..64492dda2a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/IdentityClaimTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/IdentityClaimTag.kt @@ -20,8 +20,8 @@ */ package com.vitorpamplona.quartz.nip39ExtIdentities -import android.util.Log import androidx.compose.runtime.Stable +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.ensure @Stable diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/MastodonIdentity.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/MastodonIdentity.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/MastodonIdentity.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/MastodonIdentity.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TelegramIdentity.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TelegramIdentity.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TelegramIdentity.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TelegramIdentity.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TwitterIdentity.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TwitterIdentity.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TwitterIdentity.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/TwitterIdentity.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/UnsupportedIdentity.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/UnsupportedIdentity.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/UnsupportedIdentity.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip39ExtIdentities/UnsupportedIdentity.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/ExpirationTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/ExpirationTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/ExpirationTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/ExpirationTag.kt index 92c029f11e..928bd3d79c 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/ExpirationTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/ExpirationTag.kt @@ -28,17 +28,14 @@ class ExpirationTag { companion object { const val TAG_NAME = "expiration" - @JvmStatic fun isTag(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun parse(tag: Array): Long? { ensure(tag.has(1) && tag[0] == TAG_NAME) { return null } ensure(tag[1].isNotEmpty()) { return null } return tag[1].toLongOrNull() } - @JvmStatic fun assemble(time: Long) = arrayOfNotNull(TAG_NAME, time.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip40Expiration/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/RelayAuthEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/RelayAuthEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/RelayAuthEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/RelayAuthEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/tags/ChallengeTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/tags/ChallengeTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/tags/ChallengeTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/tags/ChallengeTag.kt index 2cf0d5fae5..7ff5df5ada 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/tags/ChallengeTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/tags/ChallengeTag.kt @@ -27,7 +27,6 @@ class ChallengeTag { companion object { const val TAG_NAME = "challenge" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class ChallengeTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/tags/RelayTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/tags/RelayTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/tags/RelayTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/tags/RelayTag.kt index 498d2b19a1..c733b94e4f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/tags/RelayTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip42RelayAuth/tags/RelayTag.kt @@ -29,13 +29,10 @@ class RelayTag { companion object { const val TAG_NAME = "relay" - @JvmStatic fun match(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun notMatch(tag: Array) = !(tag.has(0) && tag[0] == TAG_NAME) - @JvmStatic fun parse(tag: Array): NormalizedRelayUrl? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -46,7 +43,6 @@ class RelayTag { return relay } - @JvmStatic fun assemble(relay: NormalizedRelayUrl) = arrayOf(TAG_NAME, relay.url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/EncryptedInfoString.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/EncryptedInfoString.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/EncryptedInfoString.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/EncryptedInfoString.kt index 4e232f63b4..f6625d50da 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/EncryptedInfoString.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/EncryptedInfoString.kt @@ -20,9 +20,12 @@ */ package com.vitorpamplona.quartz.nip44Encryption +import kotlinx.serialization.Serializable + +@Serializable class EncryptedInfoString( val ciphertext: String, val nonce: String, val v: Int, - val mac: String?, + val mac: String? = null, ) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44.kt similarity index 82% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44.kt index 43a2b2909c..cf3ff1b3ed 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.quartz.nip44Encryption -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import com.vitorpamplona.quartz.nip04Dm.crypto.EncryptedInfo import com.vitorpamplona.quartz.nip04Dm.crypto.Nip04 -import java.util.Base64 +import kotlin.io.encoding.Base64 object Nip44 { val v1 = Nip44v1() @@ -65,17 +65,17 @@ object Nip44 { // Ignores if it is not a valid json val info = try { - JsonMapper.mapper.readValue(json, EncryptedInfoString::class.java) + JsonMapper.fromJson(json) } catch (e: Exception) { - throw IllegalArgumentException("Unable to parse NIP-44 JSON: $json") + throw IllegalArgumentException("Unable to parse NIP-44 JSON: $json", e) } return when (info.v) { EncryptedInfo.V -> { val encryptedInfo = EncryptedInfo( - ciphertext = Base64.getDecoder().decode(info.ciphertext), - nonce = Base64.getDecoder().decode(info.nonce), + ciphertext = Base64.decode(info.ciphertext), + nonce = Base64.decode(info.nonce), ) Nip04.decrypt(encryptedInfo, privateKey, pubKey) } @@ -83,18 +83,21 @@ object Nip44 { Nip44v1.EncryptedInfo.V -> { val encryptedInfo = Nip44v1.EncryptedInfo( - ciphertext = Base64.getDecoder().decode(info.ciphertext), - nonce = Base64.getDecoder().decode(info.nonce), + ciphertext = Base64.decode(info.ciphertext), + nonce = Base64.decode(info.nonce), ) v1.decrypt(encryptedInfo, privateKey, pubKey) } Nip44v2.EncryptedInfo.V -> { + if (info.mac == null) { + throw IllegalArgumentException("Invalid NIP-44v2 JSON. Missing MAC: $json") + } val encryptedInfo = Nip44v2.EncryptedInfo( - ciphertext = Base64.getDecoder().decode(info.ciphertext), - nonce = Base64.getDecoder().decode(info.nonce), - mac = Base64.getDecoder().decode(info.mac), + ciphertext = Base64.decode(info.ciphertext), + nonce = Base64.decode(info.nonce), + mac = Base64.decode(info.mac), ) v2.decrypt(encryptedInfo, privateKey, pubKey) } @@ -111,7 +114,7 @@ object Nip44 { require(ciphertext.isNotBlank()) { "ciphertext must not be blank" } // Ignores if it is not base64 - val byteArray = Base64.getDecoder().decode(ciphertext) + val byteArray = Base64.decode(ciphertext) return when (byteArray[0].toInt()) { EncryptedInfo.V -> Nip04.decrypt(ciphertext, privateKey, pubKey) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v1.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v1.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v1.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v1.kt index d7f6824722..c6d5c486aa 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v1.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v1.kt @@ -25,7 +25,7 @@ import com.vitorpamplona.quartz.utils.RandomInstance import com.vitorpamplona.quartz.utils.Secp256k1Instance import com.vitorpamplona.quartz.utils.sha256.sha256 import kotlinx.coroutines.CancellationException -import java.util.Base64 +import kotlin.io.encoding.Base64 class Nip44v1 { private val sharedKeyCache = SharedKeyCache() @@ -51,7 +51,7 @@ class Nip44v1 { val cipher = LibSodiumInstance.cryptoStreamXChaCha20Xor( - messageBytes = msg.toByteArray(), + messageBytes = msg.encodeToByteArray(), nonce = nonce, key = sharedSecret, ) @@ -129,7 +129,7 @@ class Nip44v1 { fun decodePayload(payload: String): EncryptedInfo = try { - val byteArray = Base64.getDecoder().decode(payload) + val byteArray = Base64.decode(payload) check(byteArray[0].toInt() == V) EncryptedInfo( nonce = byteArray.copyOfRange(1, 25), @@ -141,11 +141,6 @@ class Nip44v1 { } } - fun encodePayload(): String = - Base64 - .getEncoder() - .encodeToString( - byteArrayOf(V.toByte()) + nonce + ciphertext, - ) + fun encodePayload(): String = Base64.encode(byteArrayOf(V.toByte()) + nonce + ciphertext) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v2.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v2.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v2.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v2.kt index 8fa099d5db..7f2ed5f298 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v2.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/Nip44v2.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.nip44Encryption.crypto.Hkdf import com.vitorpamplona.quartz.utils.RandomInstance import com.vitorpamplona.quartz.utils.Secp256k1Instance import kotlinx.coroutines.CancellationException -import java.util.Base64 +import kotlin.io.encoding.Base64 import kotlin.math.floor import kotlin.math.log2 @@ -35,7 +35,7 @@ class Nip44v2 { private val hkdf = Hkdf() private val chaCha = ChaCha20() - private val saltPrefix = "nip44-v2".toByteArray(Charsets.UTF_8) + private val saltPrefix = "nip44-v2".encodeToByteArray() private val hashLength = 32 private val minPlaintextSize: Int = 0x0001 // 1b msg => padded to 32b @@ -145,7 +145,7 @@ class Nip44v2 { } fun pad(plaintext: String): ByteArray { - val unpadded = plaintext.toByteArray(Charsets.UTF_8) + val unpadded = plaintext.encodeToByteArray() val unpaddedLen = unpadded.size check(unpaddedLen > 0) { "Message is empty ($unpaddedLen): $plaintext" } @@ -181,7 +181,7 @@ class Nip44v2 { "Invalid padding ${calcPaddedLen(unpaddedLenExt)} != $unpaddedLenExt" } - String(padded, 6, unpaddedLenExt) + padded.decodeToString(6, 6 + unpaddedLenExt) } else { check(unpaddedLenPreExt in minPlaintextSize..maxPlaintextSize) { "Invalid size $unpaddedLenPreExt not between $minPlaintextSize and $maxPlaintextSize" @@ -191,7 +191,7 @@ class Nip44v2 { "Invalid padding ${calcPaddedLen(unpaddedLenPreExt)} != $unpaddedLenPreExt" } - String(padded, 2, unpaddedLenPreExt) + padded.decodeToString(2, 2 + unpaddedLenPreExt) } } @@ -241,7 +241,7 @@ class Nip44v2 { check(payload[0] != '#') { "Unknown encryption version ${payload.get(0)}" } return try { - val byteArray = Base64.getDecoder().decode(payload) + val byteArray = Base64.decode(payload) check(byteArray[0].toInt() == V) EncryptedInfo( nonce = byteArray.copyOfRange(1, 33), @@ -255,12 +255,7 @@ class Nip44v2 { } } - fun encodePayload(): String = - Base64 - .getEncoder() - .encodeToString( - byteArrayOf(V.toByte()) + nonce + ciphertext + mac, - ) + fun encodePayload(): String = Base64.encode(byteArrayOf(V.toByte()) + nonce + ciphertext + mac) } // ----------------------------------- diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/SharedKeyCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/SharedKeyCache.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/SharedKeyCache.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/SharedKeyCache.kt index d98d89eeb9..576f0c193f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/SharedKeyCache.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/SharedKeyCache.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.quartz.nip44Encryption -import android.util.LruCache +import androidx.collection.LruCache class SharedKeyCache { private val sharedKeyCache = LruCache(200) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/ChaCha20.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/ChaCha20.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/ChaCha20.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/ChaCha20.kt index 1ddba12616..a5ef407a69 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/ChaCha20.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/ChaCha20.kt @@ -21,8 +21,6 @@ package com.vitorpamplona.quartz.nip44Encryption.crypto import com.vitorpamplona.quartz.utils.LibSodiumInstance -import javax.crypto.Cipher -import javax.crypto.spec.IvParameterSpec /** * Encapsulates the ChaCha20 options. LibSodium is faster on real hardware: 851ns vs 2,535ns encrypt/decrypt times @@ -40,6 +38,7 @@ class ChaCha20 { key: ByteArray, ) = decryptLibSodium(message, nonce, key) + /* fun encryptNative( message: ByteArray, nonce: ByteArray, @@ -59,6 +58,7 @@ class ChaCha20 { cipher.init(Cipher.DECRYPT_MODE, FixedKey(key, "ChaCha20"), IvParameterSpec(nonce)) return cipher.doFinal(message) } + */ fun encryptLibSodium( message: ByteArray, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/Hkdf.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/Hkdf.kt similarity index 88% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/Hkdf.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/Hkdf.kt index 35909b4008..f4e3bd6007 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/Hkdf.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/Hkdf.kt @@ -21,9 +21,7 @@ package com.vitorpamplona.quartz.nip44Encryption.crypto import com.vitorpamplona.quartz.nip01Core.core.toHexKey -import java.nio.ByteBuffer -import javax.crypto.Mac -import javax.crypto.spec.SecretKeySpec +import com.vitorpamplona.quartz.utils.mac.MacInstance class Hkdf( val algorithm: String = "HmacSHA256", @@ -33,9 +31,9 @@ class Hkdf( key: ByteArray, salt: ByteArray, ): ByteArray { - val mac = Mac.getInstance(algorithm) - mac.init(FixedKey(salt, algorithm)) - return mac.doFinal(key) + val mac = MacInstance(algorithm, salt) + mac.update(key) + return mac.doFinal() } fun extract( @@ -43,13 +41,14 @@ class Hkdf( key2: ByteArray, salt: ByteArray, ): ByteArray { - val mac = Mac.getInstance(algorithm) - mac.init(FixedKey(salt, algorithm)) + val mac = MacInstance(algorithm, salt) mac.update(key1) mac.update(key2) return mac.doFinal() } + /* + Old expand version for reference before we converted to the faster below. fun expand( key: ByteArray, nonce: ByteArray, @@ -82,6 +81,7 @@ class Hkdf( hmacKey = result.copyOfRange(44, 76), ) } + */ /** * Expands with outputLength == 76 while using the least amount of memory allocation @@ -95,8 +95,7 @@ class Hkdf( check(key.size == hashLen) check(nonce.size == hashLen) - val mac = Mac.getInstance(algorithm) - mac.init(FixedKey(key, algorithm)) + val mac = MacInstance(algorithm, key) // First round: T(1) = HMAC-SHA256(key, nonce || 0x01) mac.update(nonce) @@ -116,12 +115,15 @@ class Hkdf( val round3 = mac.doFinal() val hmacKey = ByteArray(hashLen) - System.arraycopy(round2, 12, hmacKey, 0, 20) - System.arraycopy(round3, 0, hmacKey, 20, 12) + + // System.arraycopy(round2, 12, hmacKey, 0, 20) + round2.copyInto(hmacKey, 0, 12, 32) + // System.arraycopy(round3, 0, hmacKey, 20, 12) + round3.copyInto(hmacKey, 20, 0, 12) // checks the mac here to avoid building a new Mac.getInstance(algorithm) if (ciphertext != null && ciphertextMac != null) { - mac.init(FixedKey(hmacKey, algorithm)) + mac.init(hmacKey, algorithm) mac.update(nonce) mac.update(ciphertext) val calculatedMac = mac.doFinal() diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/CalendarBuilder.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerMessage.kt similarity index 82% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/CalendarBuilder.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerMessage.kt index 5b317e2bdd..0b1921e92c 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/CalendarBuilder.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerMessage.kt @@ -18,13 +18,10 @@ * 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.quartz.nip03Timestamp.ots +package com.vitorpamplona.quartz.nip46RemoteSigner -interface CalendarBuilder { - fun newSyncCalendar(url: String): ICalendar +import com.vitorpamplona.quartz.nip01Core.core.OptimizedSerializable - fun newAsyncCalendar( - url: String, - digest: ByteArray, - ): ICalendarAsyncSubmit +abstract class BunkerMessage : OptimizedSerializable { + abstract fun countMemory(): Int } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequest.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequest.kt new file mode 100644 index 0000000000..acb102a1e8 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequest.kt @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2025 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.quartz.nip46RemoteSigner + +import com.vitorpamplona.quartz.utils.bytesUsedInMemory +import com.vitorpamplona.quartz.utils.pointerSizeInBytes + +open class BunkerRequest( + val id: String, + val method: String, + val params: Array = emptyArray(), +) : BunkerMessage() { + override fun countMemory(): Int = + 3 * pointerSizeInBytes + // 3 fields, 4 bytes each reference (32bit) + id.bytesUsedInMemory() + + method.bytesUsedInMemory() + + params.sumOf { pointerSizeInBytes + it.bytesUsedInMemory() } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestConnect.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestConnect.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestConnect.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestConnect.kt index c2cc17f1c2..452826528f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestConnect.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestConnect.kt @@ -21,10 +21,12 @@ package com.vitorpamplona.quartz.nip46RemoteSigner import com.vitorpamplona.quartz.nip01Core.core.HexKey -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerRequestConnect( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), val remoteKey: HexKey, val secret: HexKey? = null, val permissions: String? = null, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestGetPublicKey.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestGetPublicKey.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestGetPublicKey.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestGetPublicKey.kt index 89353d7719..d5653b0173 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestGetPublicKey.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestGetPublicKey.kt @@ -20,10 +20,12 @@ */ package com.vitorpamplona.quartz.nip46RemoteSigner -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerRequestGetPublicKey( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), ) : BunkerRequest(id, METHOD_NAME, arrayOf()) { companion object { val METHOD_NAME = "get_public_key" diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestGetRelays.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestGetRelays.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestGetRelays.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestGetRelays.kt index 0ec0f5bc61..7fffaebb01 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestGetRelays.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestGetRelays.kt @@ -20,10 +20,12 @@ */ package com.vitorpamplona.quartz.nip46RemoteSigner -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerRequestGetRelays( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), ) : BunkerRequest(id, METHOD_NAME, arrayOf()) { companion object { val METHOD_NAME = "get_relays" diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip04Decrypt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip04Decrypt.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip04Decrypt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip04Decrypt.kt index 3b21dad253..ec84fe0cf4 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip04Decrypt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip04Decrypt.kt @@ -21,10 +21,12 @@ package com.vitorpamplona.quartz.nip46RemoteSigner import com.vitorpamplona.quartz.nip01Core.core.HexKey -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerRequestNip04Decrypt( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), val pubKey: HexKey, val ciphertext: String, ) : BunkerRequest(id, METHOD_NAME, listOfNotNull(pubKey, ciphertext).toTypedArray()) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip04Encrypt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip04Encrypt.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip04Encrypt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip04Encrypt.kt index 7515513a89..bcfa133b6a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip04Encrypt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip04Encrypt.kt @@ -21,10 +21,12 @@ package com.vitorpamplona.quartz.nip46RemoteSigner import com.vitorpamplona.quartz.nip01Core.core.HexKey -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerRequestNip04Encrypt( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), val pubKey: HexKey, val message: String, ) : BunkerRequest(id, METHOD_NAME, listOfNotNull(pubKey, message).toTypedArray()) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip44Decrypt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip44Decrypt.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip44Decrypt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip44Decrypt.kt index a9e14c7f3a..ed340aaa98 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip44Decrypt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip44Decrypt.kt @@ -21,10 +21,12 @@ package com.vitorpamplona.quartz.nip46RemoteSigner import com.vitorpamplona.quartz.nip01Core.core.HexKey -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerRequestNip44Decrypt( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), val pubKey: HexKey, val ciphertext: String, ) : BunkerRequest(id, METHOD_NAME, listOfNotNull(pubKey, ciphertext).toTypedArray()) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip44Encrypt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip44Encrypt.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip44Encrypt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip44Encrypt.kt index 0777eff500..a0fdc3c8eb 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip44Encrypt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestNip44Encrypt.kt @@ -21,10 +21,12 @@ package com.vitorpamplona.quartz.nip46RemoteSigner import com.vitorpamplona.quartz.nip01Core.core.HexKey -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerRequestNip44Encrypt( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), val pubKey: HexKey, val message: String, ) : BunkerRequest(id, METHOD_NAME, listOfNotNull(pubKey, message).toTypedArray()) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestPing.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestPing.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestPing.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestPing.kt index efcefbc102..2c4b5ba157 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestPing.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestPing.kt @@ -20,10 +20,12 @@ */ package com.vitorpamplona.quartz.nip46RemoteSigner -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerRequestPing( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), ) : BunkerRequest(id, METHOD_NAME, arrayOf()) { companion object { val METHOD_NAME = "ping" diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestSign.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestSign.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestSign.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestSign.kt index 4629e489be..64747f48e5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestSign.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestSign.kt @@ -22,10 +22,12 @@ package com.vitorpamplona.quartz.nip46RemoteSigner import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerRequestSign( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), val event: EventTemplate, ) : BunkerRequest(id, METHOD_NAME, arrayOf(event.toJson())) { companion object { diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponse.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponse.kt new file mode 100644 index 0000000000..61ab484435 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponse.kt @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2025 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.quartz.nip46RemoteSigner + +import com.vitorpamplona.quartz.utils.bytesUsedInMemory +import com.vitorpamplona.quartz.utils.pointerSizeInBytes + +open class BunkerResponse( + val id: String, + val result: String?, + val error: String?, +) : BunkerMessage() { + override fun countMemory(): Int = + 3 * pointerSizeInBytes + // 3 fields, 4 bytes each reference (32bit) + id.bytesUsedInMemory() + + (result?.bytesUsedInMemory() ?: 0) + + (error?.bytesUsedInMemory() ?: 0) +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseAck.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseAck.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseAck.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseAck.kt index 23000427dd..6e979811e0 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseAck.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseAck.kt @@ -20,10 +20,12 @@ */ package com.vitorpamplona.quartz.nip46RemoteSigner -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerResponseAck( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), ) : BunkerResponse(id, RESULT, null) { companion object { val RESULT = "ack" diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseDecrypt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseDecrypt.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseDecrypt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseDecrypt.kt index 05296b7c09..d3d7def5ec 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseDecrypt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseDecrypt.kt @@ -20,10 +20,12 @@ */ package com.vitorpamplona.quartz.nip46RemoteSigner -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerResponseDecrypt( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), val plaintext: String, ) : BunkerResponse(id, plaintext, null) { companion object { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseEncrypt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseEncrypt.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseEncrypt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseEncrypt.kt index f7a579aa4c..6bd55b0bd4 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseEncrypt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseEncrypt.kt @@ -20,10 +20,12 @@ */ package com.vitorpamplona.quartz.nip46RemoteSigner -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerResponseEncrypt( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), val ciphertext: String, ) : BunkerResponse(id, ciphertext, null) { companion object { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseError.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseError.kt similarity index 84% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseError.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseError.kt index af193467ce..de7584fccc 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseError.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseError.kt @@ -20,18 +20,19 @@ */ package com.vitorpamplona.quartz.nip46RemoteSigner -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerResponseError( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), error: String, -) : com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse(id, null, error) { +) : BunkerResponse(id, null, error) { companion object { fun parse( id: String, result: String? = null, error: String, - ) = com.vitorpamplona.quartz.nip46RemoteSigner - .BunkerResponseError(id, error) + ) = BunkerResponseError(id, error) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseEvent.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseEvent.kt index a7df25d165..b5c2bf611f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseEvent.kt @@ -21,10 +21,12 @@ package com.vitorpamplona.quartz.nip46RemoteSigner import com.vitorpamplona.quartz.nip01Core.core.Event -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerResponseEvent( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), val event: Event, ) : BunkerResponse(id, event.toJson(), null) { companion object { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseGetRelays.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseGetRelays.kt similarity index 72% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseGetRelays.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseGetRelays.kt index 6ed8c94e84..d19ea1d27b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseGetRelays.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponseGetRelays.kt @@ -20,20 +20,28 @@ */ package com.vitorpamplona.quartz.nip46RemoteSigner -import com.fasterxml.jackson.core.type.TypeReference -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper -import com.vitorpamplona.quartz.nip02FollowList.ReadWrite -import java.util.UUID +import com.vitorpamplona.quartz.nip01Core.core.JsonMapper +import kotlinx.serialization.Serializable +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +// TODO: This is from Kind 3. We need to migrate to outbox +@Serializable +data class ReadWrite( + val read: Boolean, + val write: Boolean, +) + +@OptIn(ExperimentalUuidApi::class) class BunkerResponseGetRelays( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), val relays: Map, -) : BunkerResponse(id, JsonMapper.mapper.writeValueAsString(relays), null) { +) : BunkerResponse(id, JsonMapper.toJson(relays), null) { companion object { fun parse( id: String, result: String, error: String? = null, - ) = BunkerResponseGetRelays(id, JsonMapper.mapper.readValue(result, object : TypeReference>() {})) + ) = BunkerResponseGetRelays(id, JsonMapper.fromJson>(result)) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponsePong.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponsePong.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponsePong.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponsePong.kt index 8db9935964..15e5ff9c55 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponsePong.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponsePong.kt @@ -20,10 +20,12 @@ */ package com.vitorpamplona.quartz.nip46RemoteSigner -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerResponsePong( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), ) : BunkerResponse(id, RESULT, null) { companion object { val RESULT = "pong" diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponsePublicKey.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponsePublicKey.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponsePublicKey.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponsePublicKey.kt index 62acb69491..fd5cf1f587 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponsePublicKey.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerResponsePublicKey.kt @@ -21,10 +21,12 @@ package com.vitorpamplona.quartz.nip46RemoteSigner import com.vitorpamplona.quartz.nip01Core.core.HexKey -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid +@OptIn(ExperimentalUuidApi::class) class BunkerResponsePublicKey( - id: String = UUID.randomUUID().toString(), + id: String = Uuid.random().toString(), val pubkey: HexKey, ) : BunkerResponse(id, pubkey, null) { companion object { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/NostrConnectEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/NostrConnectEvent.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/NostrConnectEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/NostrConnectEvent.kt index cc07e06850..771884b8c0 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/NostrConnectEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/NostrConnectEvent.kt @@ -23,10 +23,9 @@ package com.vitorpamplona.quartz.nip46RemoteSigner import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions -import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.utils.Hex import com.vitorpamplona.quartz.utils.TimeUtils @@ -47,7 +46,7 @@ class NostrConnectEvent( if (!canDecrypt(signer)) throw SignerExceptions.UnauthorizedDecryptionException() val retVal = signer.decrypt(content, talkingWith(signer.pubKey)) - return JsonMapper.mapper.readValue(retVal, BunkerMessage::class.java) + return OptimizedJsonMapper.fromJsonTo(retVal) } private fun recipientPubKey() = tags.firstOrNull { it.size > 1 && it[0] == "p" }?.get(1) @@ -78,12 +77,11 @@ class NostrConnectEvent( kind = KIND, tags = arrayOf( - AltTag.assemble(ALT), arrayOf("p", remoteKey), ), content = signer.nip44Encrypt( - plaintext = JsonMapper.mapper.writeValueAsString(message), + plaintext = OptimizedJsonMapper.toJson(message), toPublicKey = remoteKey, ), ) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/LnZapPaymentRequestEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/LnZapPaymentRequestEvent.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/LnZapPaymentRequestEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/LnZapPaymentRequestEvent.kt index 919bc33a89..4fb9e84801 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/LnZapPaymentRequestEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/LnZapPaymentRequestEvent.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.quartz.nip47WalletConnect import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip31Alts.AltTag @@ -49,7 +49,7 @@ class LnZapPaymentRequestEvent( suspend fun decryptRequest(signer: NostrSigner): Request { if (!canDecrypt(signer)) throw SignerExceptions.UnauthorizedDecryptionException() val jsonText = signer.decrypt(content, talkingWith(signer.pubKey)) - return JsonMapper.mapper.readValue(jsonText, Request::class.java) + return OptimizedJsonMapper.fromJsonTo(jsonText) } companion object { @@ -62,7 +62,7 @@ class LnZapPaymentRequestEvent( signer: NostrSigner, createdAt: Long = TimeUtils.now(), ): LnZapPaymentRequestEvent { - val serializedRequest = JsonMapper.mapper.writeValueAsString(PayInvoiceMethod.create(lnInvoice)) + val serializedRequest = OptimizedJsonMapper.toJson(PayInvoiceMethod.create(lnInvoice)) val tags = arrayOf(arrayOf("p", walletServicePubkey), AltTag.assemble(ALT)) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/LnZapPaymentResponseEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/LnZapPaymentResponseEvent.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/LnZapPaymentResponseEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/LnZapPaymentResponseEvent.kt index 1f019bac67..0d2f0f6255 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/LnZapPaymentResponseEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/LnZapPaymentResponseEvent.kt @@ -23,7 +23,7 @@ package com.vitorpamplona.quartz.nip47WalletConnect import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions @@ -50,7 +50,7 @@ class LnZapPaymentResponseEvent( if (!canDecrypt(signer)) throw SignerExceptions.UnauthorizedDecryptionException() val json = signer.decrypt(content, talkingWith(signer.pubKey)) - return JsonMapper.mapper.readValue(json, Response::class.java) + return OptimizedJsonMapper.fromJsonTo(json) } companion object { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Nip47WalletConnect.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Nip47WalletConnect.kt similarity index 85% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Nip47WalletConnect.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Nip47WalletConnect.kt index c3cf1add28..c906515d62 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Nip47WalletConnect.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Nip47WalletConnect.kt @@ -20,15 +20,15 @@ */ package com.vitorpamplona.quartz.nip47WalletConnect -import androidx.core.net.toUri -import com.fasterxml.jackson.module.kotlin.readValue import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.JsonMapper import com.vitorpamplona.quartz.nip01Core.core.toHexKey -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip19Bech32.decodePublicKey +import com.vitorpamplona.quartz.utils.UriParser import kotlinx.coroutines.CancellationException +import kotlinx.serialization.Serializable // Rename to the corect nip number when ready. class Nip47WalletConnect { @@ -36,13 +36,13 @@ class Nip47WalletConnect { fun parse(uri: String): Nip47URINorm { // nostrwalletconnect://b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io&metadata=%7B%22name%22%3A%22Example%22%7D - val url = uri.toUri() + val url = UriParser(uri) - if (url.scheme != "nostrwalletconnect" && url.scheme != "nostr+walletconnect") { + if (url.scheme() != "nostrwalletconnect" && url.scheme() != "nostr+walletconnect") { throw IllegalArgumentException("Not a Wallet Connect QR Code") } - val pubkey = url.host ?: throw IllegalArgumentException("Hostname cannot be null") + val pubkey = url.host() ?: throw IllegalArgumentException("Hostname cannot be null") val pubkeyHex = try { @@ -60,6 +60,7 @@ class Nip47WalletConnect { } } + @Serializable data class Nip47URI( val pubKeyHex: HexKey, val relayUri: String, @@ -75,9 +76,9 @@ class Nip47WalletConnect { } companion object { - fun parser(json: String) = JsonMapper.mapper.readValue(json) + fun parser(json: String) = JsonMapper.fromJson(json) - fun serializer(value: Nip47URI) = JsonMapper.mapper.writeValueAsString(value) + fun serializer(value: Nip47URI) = JsonMapper.toJson(value) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/NostrWalletConnectRequestCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/NostrWalletConnectRequestCache.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/NostrWalletConnectRequestCache.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/NostrWalletConnectRequestCache.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/NostrWalletConnectResponseCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/NostrWalletConnectResponseCache.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/NostrWalletConnectResponseCache.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/NostrWalletConnectResponseCache.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Request.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Request.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Request.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Request.kt index 1bb56fc6e0..584842277b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Request.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Request.kt @@ -20,10 +20,12 @@ */ package com.vitorpamplona.quartz.nip47WalletConnect +import com.vitorpamplona.quartz.nip01Core.core.OptimizedSerializable + // REQUEST OBJECTS abstract class Request( var method: String? = null, -) +) : OptimizedSerializable // PayInvoice Call class PayInvoiceParams( diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Response.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Response.kt similarity index 84% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Response.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Response.kt index 9f53733652..4dc25157ac 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Response.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/Response.kt @@ -20,14 +20,14 @@ */ package com.vitorpamplona.quartz.nip47WalletConnect -import com.fasterxml.jackson.annotation.JsonProperty +import com.vitorpamplona.quartz.nip01Core.core.OptimizedSerializable import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.pointerSizeInBytes // RESPONSE OBJECTS abstract class Response( - @field:JsonProperty("result_type") val resultType: String, -) { + val resultType: String, +) : OptimizedSerializable { abstract fun countMemory(): Int } @@ -58,39 +58,30 @@ class PayInvoiceErrorResponse( override fun countMemory(): Int = pointerSizeInBytes + (error?.countMemory() ?: 0) enum class ErrorType { - @JsonProperty(value = "RATE_LIMITED") RATE_LIMITED, // The client is sending commands too fast. It should retry in a few seconds. - @JsonProperty(value = "NOT_IMPLEMENTED") NOT_IMPLEMENTED, // The command is not known or is intentionally not implemented. - @JsonProperty(value = "INSUFFICIENT_BALANCE") INSUFFICIENT_BALANCE, // The command is not known or is intentionally not implemented. - @JsonProperty(value = "PAYMENT_FAILED") PAYMENT_FAILED, // The wallet does not have enough funds to cover a fee reserve or the payment amount. - @JsonProperty(value = "QUOTA_EXCEEDED") QUOTA_EXCEEDED, // The wallet has exceeded its spending quota. - @JsonProperty(value = "RESTRICTED") RESTRICTED, // This public key is not allowed to do this operation. - @JsonProperty(value = "UNAUTHORIZED") UNAUTHORIZED, // This public key has no wallet connected. - @JsonProperty(value = "INTERNAL") INTERNAL, // An internal error. - @JsonProperty(value = "OTHER") OTHER, // Other error. } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/ProxyTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/ProxyTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/ProxyTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/ProxyTag.kt index e2bb5591fe..5d41c61e3f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/ProxyTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/ProxyTag.kt @@ -38,17 +38,14 @@ data class ProxyTag( companion object { const val TAG_NAME = "proxy" - @JvmStatic fun isTagged(tag: Array) = tag.has(2) && tag[0] == TAG_NAME && tag[1].isNotEmpty() && tag[2].isNotEmpty() - @JvmStatic fun parse(tags: Array): ProxyTag? { ensure(tags.has(2)) { return null } ensure(tags[0] == TAG_NAME) { return null } return ProxyTag(tags[1], tags[2]) } - @JvmStatic fun assemble( id: String, protocol: String, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip48ProxyTags/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/ByteArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/ByteArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/ByteArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/ByteArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49.kt similarity index 89% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49.kt index 66421f5ef0..4719dcec13 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/Nip49.kt @@ -20,14 +20,15 @@ */ package com.vitorpamplona.quartz.nip49PrivKeyEnc -import android.util.Log import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip19Bech32.bech32.bechToBytes import com.vitorpamplona.quartz.utils.LibSodiumInstance +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.RandomInstance -import java.text.Normalizer +import com.vitorpamplona.quartz.utils.UnicodeNormalizer +import kotlin.math.pow class Nip49 { fun decrypt( @@ -42,8 +43,8 @@ class Nip49 { check(encryptedInfo != null) { "Couldn't decode key" } check(encryptedInfo.version == EncryptedInfo.V) { "invalid version" } - val normalizedPassword = Normalizer.normalize(password, Normalizer.Form.NFKC).toByteArray(Charsets.UTF_8) - val n = Math.pow(2.0, encryptedInfo.logn.toDouble()).toInt() + val normalizedPassword = UnicodeNormalizer().normalizeNFKC(password).encodeToByteArray() + val n = 2.0.pow(encryptedInfo.logn.toDouble()).toInt() val key = SCrypt.scrypt(normalizedPassword, encryptedInfo.salt, n, 8, 1, 32) val m = ByteArray(32) @@ -78,8 +79,8 @@ class Nip49 { val salt = RandomInstance.bytes(16) val nonce = RandomInstance.bytes(24) - val normalizedPassword = Normalizer.normalize(password, Normalizer.Form.NFKC).toByteArray(Charsets.UTF_8) - val n = Math.pow(2.0, logn.toDouble()).toInt() + val normalizedPassword = UnicodeNormalizer().normalizeNFKC(password).encodeToByteArray() + val n = 2.0.pow(logn.toDouble()).toInt() val key = SCrypt.scrypt(normalizedPassword, salt, n, 8, 1, 32) val ciphertext = ByteArray(48) @@ -147,9 +148,6 @@ class Nip49 { } // ln(n.toDouble()).toInt().toByte(), - fun encodePayload(): String = - ( - byteArrayOf(version, logn) + salt + nonce + keySecurity + encryptedKey - ).toNCryptSec() + fun encodePayload(): String = (byteArrayOf(version, logn) + salt + nonce + keySecurity + encryptedKey).toNCryptSec() } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/PBKDF.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/PBKDF.kt similarity index 81% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/PBKDF.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/PBKDF.kt index bcfbcfc6e3..5a8ec18ec7 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/PBKDF.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip49PrivKeyEnc/PBKDF.kt @@ -20,9 +20,7 @@ */ package com.vitorpamplona.quartz.nip49PrivKeyEnc -import java.security.GeneralSecurityException -import javax.crypto.Mac -import javax.crypto.spec.SecretKeySpec +import com.vitorpamplona.quartz.utils.mac.MacInstance import kotlin.math.ceil import kotlin.math.pow @@ -43,10 +41,7 @@ object PBKDF { * @param dkLen Intended length, in octets, of the derived key. * * @return The derived key. - * - * @throws GeneralSecurityException */ - @Throws(GeneralSecurityException::class) fun pbkdf2( alg: String, password: ByteArray, @@ -54,8 +49,7 @@ object PBKDF { iterationCount: Int, dkLen: Int, ): ByteArray { - val mac = Mac.getInstance(alg) - mac.init(SecretKeySpec(password, alg)) + val mac = MacInstance(alg, password) val destKey = ByteArray(dkLen) pbkdf2(mac, salt, iterationCount, destKey, dkLen) return destKey @@ -64,18 +58,15 @@ object PBKDF { /** * Implementation of PBKDF2 (RFC2898). * - * @param mac Pre-initialized [Mac] instance to use. + * @param mac Pre-initialized Mac instance to use. * @param salt Salt. * @param c Iteration count. * @param destKey Byte array that derived key will be placed in. * @param dkLen Intended length, in octets, of the derived key. - * - * @throws GeneralSecurityException */ - @JvmStatic - @Throws(GeneralSecurityException::class) + fun pbkdf2( - mac: Mac, + mac: MacInstance, salt: ByteArray, c: Int, destKey: ByteArray, @@ -84,7 +75,7 @@ object PBKDF { val hLen = mac.getMacLength() if (dkLen > (2.0.pow(32.0) - 1) * hLen) { - throw GeneralSecurityException("Requested key length too long") + throw IllegalArgumentException("Requested key length too long") } val uArray = ByteArray(hLen) @@ -94,7 +85,8 @@ object PBKDF { val l = ceil(dkLen.toDouble() / hLen).toInt() val r = dkLen - (l - 1) * hLen - System.arraycopy(salt, 0, block1, 0, salt.size) + // System.arraycopy(salt, 0, block1, 0, salt.size) + salt.copyInto(block1, 0, 0, salt.size) for (i in 1..l) { block1[salt.size + 0] = (i shr 24 and 0xff).toByte() @@ -104,7 +96,9 @@ object PBKDF { mac.update(block1) mac.doFinal(uArray, 0) - System.arraycopy(uArray, 0, rArray, 0, hLen) + + // System.arraycopy(uArray, 0, rArray, 0, hLen) + uArray.copyInto(rArray, 0, 0, hLen) for (j in 1.. 0) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip50Search/SearchRelayListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip50Search/SearchRelayListEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip50Search/SearchRelayListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip50Search/SearchRelayListEvent.kt index 93f389cf04..b0816ef19a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip50Search/SearchRelayListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip50Search/SearchRelayListEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip50Search import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @@ -28,8 +29,7 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip50Search/SearchableEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip50Search/SearchableEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip50Search/SearchableEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip50Search/SearchableEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PinListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PinListEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PinListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PinListEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayBuilder.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayBuilder.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayBuilder.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayBuilder.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayEventCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayEventCache.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayEventCache.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/PrivateTagArrayEventCache.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/BookmarkListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/BookmarkListEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/BookmarkListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/BookmarkListEvent.kt index eca37af6de..0459ad5f07 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/BookmarkListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/BookmarkListEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip51Lists.bookmarkList import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder @@ -30,8 +31,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/AddressBookmark.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/AddressBookmark.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/AddressBookmark.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/AddressBookmark.kt index 02e0fbd10f..92d11a5989 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/AddressBookmark.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/AddressBookmark.kt @@ -20,12 +20,12 @@ */ package com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.ensure @@ -46,34 +46,28 @@ class AddressBookmark( companion object { const val TAG_NAME = "a" - @JvmStatic fun isTagged(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun isTagged( tag: Array, addressId: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == addressId - @JvmStatic fun isTagged( tag: Array, address: AddressBookmark, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == address.toTag() - @JvmStatic fun isIn( tag: Array, addressIds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in addressIds - @JvmStatic fun isTaggedWithKind( tag: Array, kind: String, ) = tag.has(1) && tag[0] == TAG_NAME && Address.isOfKind(tag[1], kind) - @JvmStatic fun parse( aTagId: String, relay: String?, @@ -81,7 +75,6 @@ class AddressBookmark( AddressBookmark(it, relay?.let { RelayUrlNormalizer.normalizeOrNull(it) }) } - @JvmStatic fun parse(tag: Array): AddressBookmark? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -89,7 +82,6 @@ class AddressBookmark( return parse(tag[1], tag.getOrNull(2)) } - @JvmStatic fun parseValidAddress(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -97,7 +89,6 @@ class AddressBookmark( return Address.parse(tag[1])?.toValue() } - @JvmStatic fun parseAddress(tag: Array): Address? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -105,7 +96,6 @@ class AddressBookmark( return Address.parse(tag[1]) } - @JvmStatic fun parseAddressId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -113,7 +103,6 @@ class AddressBookmark( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): AddressHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -127,19 +116,16 @@ class AddressBookmark( return AddressHint(tag[1], relayHint) } - @JvmStatic fun assemble( aTagId: HexKey, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, aTagId, relay?.url) - @JvmStatic fun assemble( address: Address, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, address.toValue(), relay?.url) - @JvmStatic fun assemble( kind: Int, pubKey: String, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/BookmarkIdTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/BookmarkIdTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/BookmarkIdTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/BookmarkIdTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/EventBookmark.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/EventBookmark.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/EventBookmark.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/EventBookmark.kt index 82de81214d..f81bcf2a31 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/EventBookmark.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/bookmarkList/tags/EventBookmark.kt @@ -53,16 +53,13 @@ class EventBookmark( companion object { const val TAG_NAME = "e" - @JvmStatic fun isTagged(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].length == 64 - @JvmStatic fun isTagged( tag: Array, eventId: HexKey, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == eventId - @JvmStatic fun parse(tag: Array): EventBookmark? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -71,7 +68,6 @@ class EventBookmark( return EventBookmark(tag[1], pickRelayHint(tag), pickAuthor(tag)) } - @JvmStatic fun parseId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -79,7 +75,6 @@ class EventBookmark( return tag[1] } - @JvmStatic private fun pickRelayHint(tag: Array): NormalizedRelayUrl? { if (tag.has(2) && tag[2].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[2])) return RelayUrlNormalizer.normalizeOrNull(tag[2]) if (tag.has(3) && tag[3].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[3])) return RelayUrlNormalizer.normalizeOrNull(tag[3]) @@ -87,7 +82,6 @@ class EventBookmark( return null } - @JvmStatic private fun pickAuthor(tag: Array): HexKey? { if (tag.has(2) && tag[2].length == 64) return tag[2] if (tag.has(3) && tag[3].length == 64) return tag[3] @@ -95,7 +89,6 @@ class EventBookmark( return null } - @JvmStatic fun parseAsHint(tag: Array): EventIdHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -109,7 +102,6 @@ class EventBookmark( return EventIdHint(tag[1], hint) } - @JvmStatic fun assemble( eventId: HexKey, relay: NormalizedRelayUrl?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/encryption/NostrSignerExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/encryption/NostrSignerExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/encryption/NostrSignerExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/encryption/NostrSignerExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/encryption/PrivateTagsInContent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/encryption/PrivateTagsInContent.kt similarity index 87% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/encryption/PrivateTagsInContent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/encryption/PrivateTagsInContent.kt index daaab9d291..29c7b4d12a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/encryption/PrivateTagsInContent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/encryption/PrivateTagsInContent.kt @@ -20,19 +20,18 @@ */ package com.vitorpamplona.quartz.nip51Lists.encryption -import android.util.Log -import com.fasterxml.jackson.core.JsonParseException -import com.fasterxml.jackson.module.kotlin.readValue +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper import com.vitorpamplona.quartz.nip01Core.core.TagArray -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync +import com.vitorpamplona.quartz.utils.Log +import kotlinx.coroutines.CancellationException class PrivateTagsInContent { companion object { - fun decode(content: String) = JsonMapper.mapper.readValue>>(content) + fun decode(content: String) = OptimizedJsonMapper.fromJsonToTagArray(content) - fun encode(privateTags: Array>): String = JsonMapper.mapper.writeValueAsString(privateTags) + fun encode(privateTags: Array>): String = OptimizedJsonMapper.toJson(privateTags) suspend fun decrypt( content: String, @@ -42,7 +41,8 @@ class PrivateTagsInContent { val json = signer.decrypt(content, signer.pubKey) return try { decode(json) - } catch (e: JsonParseException) { + } catch (e: Exception) { + if (e is CancellationException) throw e Log.w("DraftEvent", "Unable to parse inner event of a draft: $json") throw e } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/FollowListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/FollowListEvent.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/FollowListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/FollowListEvent.kt index 3a447e9623..34dc78e70a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/FollowListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/FollowListEvent.kt @@ -28,7 +28,7 @@ import com.vitorpamplona.quartz.nip01Core.core.fastAny import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip51Lists.muteList.tags.UserTag @@ -37,7 +37,8 @@ import com.vitorpamplona.quartz.nip51Lists.tags.DescriptionTag import com.vitorpamplona.quartz.nip51Lists.tags.ImageTag import com.vitorpamplona.quartz.nip51Lists.tags.TitleTag import com.vitorpamplona.quartz.utils.TimeUtils -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable class FollowListEvent( @@ -69,11 +70,12 @@ class FollowListEvent( const val KIND = 39089 const val ALT = "List of people to follow" + @OptIn(ExperimentalUuidApi::class) suspend fun create( name: String, person: UserTag, signer: NostrSigner, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), ): FollowListEvent = create( @@ -133,21 +135,23 @@ class FollowListEvent( return signer.sign(createdAt, KIND, newTags, content) } + @OptIn(ExperimentalUuidApi::class) suspend fun create( name: String, people: List = emptyList(), signer: NostrSigner, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), ): FollowListEvent { val template = build(name, people, dTag, createdAt) return signer.sign(template) } + @OptIn(ExperimentalUuidApi::class) fun build( name: String, people: List = emptyList(), - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = eventTemplate( diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/followList/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/GeohashListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/GeohashListEvent.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/GeohashListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/GeohashListEvent.kt index ad98fd7783..39d2230d62 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/GeohashListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/GeohashListEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip51Lists.geohashList import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder @@ -29,7 +30,6 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHashTag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/geohashList/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/HashtagListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/HashtagListEvent.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/HashtagListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/HashtagListEvent.kt index 3d4e8bb493..ccc0e45aaf 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/HashtagListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/HashtagListEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip51Lists.hashtagList import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder @@ -29,7 +30,6 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip01Core.tags.hashtags.HashtagTag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/hashtagList/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/MuteListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/MuteListEvent.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/MuteListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/MuteListEvent.kt index 25880d8363..f24f4b6c40 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/MuteListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/MuteListEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip51Lists.muteList import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder @@ -29,7 +30,6 @@ import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/MuteTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/MuteTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/MuteTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/MuteTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/UserTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/UserTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/UserTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/UserTag.kt index 69fd21af1b..c67a1fdbf0 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/UserTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/UserTag.kt @@ -61,7 +61,6 @@ class UserTag( key: HexKey, ): Boolean = tag.has(1) && tag[0] == TAG_NAME && tag[1] == key - @JvmStatic fun parse(tag: Tag): UserTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -72,7 +71,6 @@ class UserTag( return UserTag(tag[1], hint) } - @JvmStatic fun parseKey(tag: Array): HexKey? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -80,7 +78,6 @@ class UserTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): PubKeyHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -94,7 +91,6 @@ class UserTag( return PubKeyHint(tag[1], hint) } - @JvmStatic fun assemble( pubkey: HexKey, relayHint: NormalizedRelayUrl?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/WordTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/WordTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/WordTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/WordTag.kt index 9a1010c89f..cb87f97faa 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/WordTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/muteList/tags/WordTag.kt @@ -42,16 +42,13 @@ class WordTag( companion object { const val TAG_NAME = "word" - @JvmStatic fun isTagged(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun isTagged( tag: Array, word: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == word - @JvmStatic fun parse(tag: Array): WordTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -60,7 +57,6 @@ class WordTag( return WordTag(tag[1]) } - @JvmStatic fun parseId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -68,7 +64,6 @@ class WordTag( return tag[1] } - @JvmStatic fun assemble(word: String) = arrayOfNotNull(TAG_NAME, word) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/PeopleListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/PeopleListEvent.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/PeopleListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/PeopleListEvent.kt index 2292a4c414..145a08738e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/PeopleListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/PeopleListEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip51Lists.peopleList import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder @@ -29,8 +30,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip23LongContent.tags.TitleTag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt @@ -42,7 +42,8 @@ import com.vitorpamplona.quartz.nip51Lists.remove import com.vitorpamplona.quartz.nip51Lists.tags.DescriptionTag import com.vitorpamplona.quartz.nip51Lists.tags.NameTag import com.vitorpamplona.quartz.utils.TimeUtils -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable class PeopleListEvent( @@ -84,12 +85,13 @@ class PeopleListEvent( fun blockListFor(pubKeyHex: HexKey): String = "30000:$pubKeyHex:$BLOCK_LIST_D_TAG" + @OptIn(ExperimentalUuidApi::class) suspend fun create( name: String, person: UserTag, isPrivate: Boolean, signer: NostrSigner, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), ): PeopleListEvent = if (isPrivate) { @@ -180,24 +182,26 @@ class PeopleListEvent( return signer.sign(createdAt, KIND, newTags, content) } + @OptIn(ExperimentalUuidApi::class) suspend fun create( name: String, publicPeople: List = emptyList(), privatePeople: List = emptyList(), signer: NostrSigner, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), ): PeopleListEvent { val template = build(name, publicPeople, privatePeople, signer, dTag, createdAt) return signer.sign(template) } + @OptIn(ExperimentalUuidApi::class) suspend fun build( name: String, publicPeople: List = emptyList(), privatePeople: List = emptyList(), signer: NostrSigner, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = eventTemplate( diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/peopleList/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/BlockedRelayListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/BlockedRelayListEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/BlockedRelayListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/BlockedRelayListEvent.kt index 60845fbcb5..d2900444d4 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/BlockedRelayListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/BlockedRelayListEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip51Lists.relayLists import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @@ -28,8 +29,7 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/BroadcastRelayListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/BroadcastRelayListEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/BroadcastRelayListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/BroadcastRelayListEvent.kt index b703a6f7b7..dd50a8a1f8 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/BroadcastRelayListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/BroadcastRelayListEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip51Lists.relayLists import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @@ -28,8 +29,7 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/IndexerRelayListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/IndexerRelayListEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/IndexerRelayListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/IndexerRelayListEvent.kt index 23b24847cd..3a20129fcd 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/IndexerRelayListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/IndexerRelayListEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip51Lists.relayLists import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @@ -28,8 +29,7 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/ProxyRelayListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/ProxyRelayListEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/ProxyRelayListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/ProxyRelayListEvent.kt index 9dc50d9785..cc7987c20c 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/ProxyRelayListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/ProxyRelayListEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip51Lists.relayLists import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @@ -28,8 +29,7 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/TrustedRelayListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/TrustedRelayListEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/TrustedRelayListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/TrustedRelayListEvent.kt index 9edd62937b..7ed8fb36e8 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/TrustedRelayListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/TrustedRelayListEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip51Lists.relayLists import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @@ -28,8 +29,7 @@ import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/RelayTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/RelayTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/RelayTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/RelayTag.kt index bc24afe51c..693ac5cac7 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/RelayTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/RelayTag.kt @@ -29,13 +29,10 @@ class RelayTag { companion object { const val TAG_NAME = "relay" - @JvmStatic fun match(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun notMatch(tag: Array) = !(tag.has(0) && tag[0] == TAG_NAME) - @JvmStatic fun parse(tag: Array): NormalizedRelayUrl? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -46,7 +43,6 @@ class RelayTag { return relay } - @JvmStatic fun assemble(relay: NormalizedRelayUrl) = arrayOf(TAG_NAME, relay.url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relayLists/tags/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relaySets/RelaySetEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relaySets/RelaySetEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relaySets/RelaySetEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/relaySets/RelaySetEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/DescriptionTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/DescriptionTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/DescriptionTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/DescriptionTag.kt index ee956a08c4..4d7157d0aa 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/DescriptionTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/DescriptionTag.kt @@ -24,13 +24,11 @@ class DescriptionTag { companion object { const val TAG_NAME = "description" - @JvmStatic fun parse(tag: Array): String? { if (tag.size < 2 || tag[0] != TAG_NAME || tag[1].isEmpty()) return null return tag[1] } - @JvmStatic fun assemble(name: String) = arrayOf(TAG_NAME, name) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/ImageTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/ImageTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/ImageTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/ImageTag.kt index 90bb59757d..7dd334d663 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/ImageTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/ImageTag.kt @@ -24,13 +24,11 @@ class ImageTag { companion object { const val TAG_NAME = "image" - @JvmStatic fun parse(tag: Array): String? { if (tag.size < 2 || tag[0] != TAG_NAME || tag[1].isEmpty()) return null return tag[1] } - @JvmStatic fun assemble(name: String) = arrayOf(TAG_NAME, name) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/NameTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/NameTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/NameTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/NameTag.kt index bb32b09212..f5a4fbca19 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/NameTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/NameTag.kt @@ -24,13 +24,11 @@ class NameTag { companion object { const val TAG_NAME = "name" - @JvmStatic fun parse(tag: Array): String? { if (tag.size < 2 || tag[0] != TAG_NAME || tag[1].isEmpty()) return null return tag[1] } - @JvmStatic fun assemble(name: String) = arrayOf(TAG_NAME, name) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/RelayTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/RelayTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/RelayTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/RelayTag.kt index d56776690b..d38c1ab1b1 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/RelayTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/RelayTag.kt @@ -29,13 +29,10 @@ class RelayTag { companion object { const val TAG_NAME = "r" - @JvmStatic fun match(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun notMatch(tag: Array) = !(tag.has(0) && tag[0] == TAG_NAME) - @JvmStatic fun parse(tag: Array): NormalizedRelayUrl? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -46,7 +43,6 @@ class RelayTag { return relay } - @JvmStatic fun assemble(relay: NormalizedRelayUrl) = arrayOf(TAG_NAME, relay.url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/TitleTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/TitleTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/TitleTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/TitleTag.kt index 5687d5fbf5..7c8e1c9300 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/TitleTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip51Lists/tags/TitleTag.kt @@ -24,13 +24,11 @@ class TitleTag { companion object { const val TAG_NAME = "title" - @JvmStatic fun parse(tag: Array): String? { if (tag.size < 2 || tag[0] != TAG_NAME || tag[1].isEmpty()) return null return tag[1] } - @JvmStatic fun assemble(name: String) = arrayOf(TAG_NAME, name) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarDateSlotEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarDateSlotEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarDateSlotEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarDateSlotEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarRSVPEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarRSVPEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarRSVPEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarRSVPEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarTimeSlotEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarTimeSlotEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarTimeSlotEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarTimeSlotEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/chat/LiveActivitiesChatMessageEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/chat/LiveActivitiesChatMessageEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/chat/LiveActivitiesChatMessageEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/chat/LiveActivitiesChatMessageEvent.kt index 1ecedc91ef..f141536fdb 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/chat/LiveActivitiesChatMessageEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/chat/LiveActivitiesChatMessageEvent.kt @@ -32,8 +32,8 @@ import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.aTag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.aTag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip10Notes.BaseThreadedEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/chat/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/chat/TagArrayBuilderExt.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/chat/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/chat/TagArrayBuilderExt.kt index 05814441c1..d5f7a283d1 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/chat/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/chat/TagArrayBuilderExt.kt @@ -22,11 +22,13 @@ package com.vitorpamplona.quartz.nip53LiveActivities.chat import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.toATag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTags import com.vitorpamplona.quartz.nip10Notes.tags.MarkedETag +import com.vitorpamplona.quartz.nip10Notes.tags.toMarkedETag import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent fun TagArrayBuilder.activity(rep: ATag) = addUnique(rep.toATagArray()) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/MeetingRoomEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/MeetingRoomEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/MeetingRoomEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/MeetingRoomEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/MeetingSpaceEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/MeetingSpaceEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/MeetingSpaceEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/MeetingSpaceEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/EndpointUrlTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/EndpointUrlTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/EndpointUrlTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/EndpointUrlTag.kt index 56961287a7..9663dc0edf 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/EndpointUrlTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/EndpointUrlTag.kt @@ -27,7 +27,6 @@ class EndpointUrlTag { companion object Companion { const val TAG_NAME = "endpoint" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class EndpointUrlTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/MeetingSpaceTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/MeetingSpaceTag.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/MeetingSpaceTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/MeetingSpaceTag.kt index cfe3463115..c43eb30d81 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/MeetingSpaceTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/MeetingSpaceTag.kt @@ -20,12 +20,12 @@ */ package com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.ensure @@ -46,34 +46,28 @@ class MeetingSpaceTag( companion object Companion { const val TAG_NAME = "a" - @JvmStatic fun isTagged(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun isTagged( tag: Array, addressId: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == addressId - @JvmStatic fun isTagged( tag: Array, address: MeetingSpaceTag, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == address.toTag() - @JvmStatic fun isIn( tag: Array, addressIds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in addressIds - @JvmStatic fun isTaggedWithKind( tag: Array, kind: String, ) = tag.has(1) && tag[0] == TAG_NAME && Address.isOfKind(tag[1], kind) - @JvmStatic fun parse( aTagId: String, relay: String?, @@ -81,7 +75,6 @@ class MeetingSpaceTag( MeetingSpaceTag(it, relay?.let { RelayUrlNormalizer.normalizeOrNull(it) }) } - @JvmStatic fun parse(tag: Array): MeetingSpaceTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -89,7 +82,6 @@ class MeetingSpaceTag( return parse(tag[1], tag.getOrNull(2)) } - @JvmStatic fun parseValidAddress(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -97,7 +89,6 @@ class MeetingSpaceTag( return Address.parse(tag[1])?.toValue() } - @JvmStatic fun parseAddress(tag: Array): Address? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -105,7 +96,6 @@ class MeetingSpaceTag( return Address.parse(tag[1]) } - @JvmStatic fun parseAddressId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -113,7 +103,6 @@ class MeetingSpaceTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): AddressHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -127,19 +116,16 @@ class MeetingSpaceTag( return AddressHint(tag[1], relayHint) } - @JvmStatic fun assemble( aTagId: HexKey, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, aTagId, relay?.url) - @JvmStatic fun assemble( address: Address, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, address.toValue(), relay?.url) - @JvmStatic fun assemble( kind: Int, pubKey: String, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RecordingTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RecordingTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RecordingTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RecordingTag.kt index df2d007df9..96cb8de3c5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RecordingTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RecordingTag.kt @@ -27,7 +27,6 @@ class RecordingTag { companion object { const val TAG_NAME = "recording" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class RecordingTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RelayListTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RelayListTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RelayListTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RelayListTag.kt index c1e82b1ccd..d76e187678 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RelayListTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RelayListTag.kt @@ -29,7 +29,6 @@ class RelayListTag { companion object { const val TAG_NAME = "relays" - @JvmStatic fun parse(tag: Array): List? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -44,7 +43,6 @@ class RelayListTag { return relays } - @JvmStatic fun assemble(urls: List) = arrayOf(TAG_NAME) + urls.map { it.url }.toTypedArray() } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RoomNameTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RoomNameTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RoomNameTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RoomNameTag.kt index b0cd4dfd3d..e56012bf60 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RoomNameTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/RoomNameTag.kt @@ -27,7 +27,6 @@ class RoomNameTag { companion object Companion { const val TAG_NAME = "room" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class RoomNameTag { return tag[1] } - @JvmStatic fun assemble(title: String) = arrayOf(TAG_NAME, title) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/ServiceUrlTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/ServiceUrlTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/ServiceUrlTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/ServiceUrlTag.kt index 063048451b..6d75575b74 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/ServiceUrlTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/ServiceUrlTag.kt @@ -27,7 +27,6 @@ class ServiceUrlTag { companion object Companion { const val TAG_NAME = "service" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class ServiceUrlTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/StatusTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/StatusTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/StatusTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/StatusTag.kt index 99440c1452..784596f0a3 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/StatusTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/meetingSpaces/tags/StatusTag.kt @@ -48,7 +48,6 @@ class StatusTag { companion object { const val TAG_NAME = "status" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -56,7 +55,6 @@ class StatusTag { return tag[1] } - @JvmStatic fun parseEnum(tag: Array): STATUS? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -64,7 +62,6 @@ class StatusTag { return STATUS.parse(tag[1]) } - @JvmStatic fun assemble(status: STATUS) = arrayOf(TAG_NAME, status.code) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/MeetingRoomPresenceEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/MeetingRoomPresenceEvent.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/MeetingRoomPresenceEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/MeetingRoomPresenceEvent.kt index 4919302c70..eff119979a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/MeetingRoomPresenceEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/MeetingRoomPresenceEvent.kt @@ -21,14 +21,14 @@ package com.vitorpamplona.quartz.nip53LiveActivities.presence import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingRoomEvent import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.MeetingSpaceTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/TagArrayBuilderExt.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/TagArrayBuilderExt.kt index 138e7ea5f2..636f3c0d21 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/TagArrayBuilderExt.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.quartz.nip53LiveActivities.presence import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle +import com.vitorpamplona.quartz.nip01Core.tags.aTag.toATag import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingRoomEvent import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.MeetingSpaceTag import com.vitorpamplona.quartz.nip53LiveActivities.presence.tags.HandRaisedTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/tags/HandRaisedTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/tags/HandRaisedTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/tags/HandRaisedTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/tags/HandRaisedTag.kt index bf3646c0a0..8f3c1cddfb 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/tags/HandRaisedTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/tags/HandRaisedTag.kt @@ -27,7 +27,6 @@ class HandRaisedTag { companion object Companion { const val TAG_NAME = "hand" - @JvmStatic fun parse(tag: Array): Boolean? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class HandRaisedTag { return tag[1] == "1" } - @JvmStatic fun assemble(handRaised: Boolean) = arrayOf(TAG_NAME, if (handRaised) "1" else "0") } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/tags/MeetingRoomTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/tags/MeetingRoomTag.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/tags/MeetingRoomTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/tags/MeetingRoomTag.kt index c5c9062c71..1c487501be 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/tags/MeetingRoomTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/presence/tags/MeetingRoomTag.kt @@ -20,12 +20,12 @@ */ package com.vitorpamplona.quartz.nip53LiveActivities.presence.tags +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.ensure @@ -46,34 +46,28 @@ class MeetingRoomTag( companion object Companion { const val TAG_NAME = "a" - @JvmStatic fun isTagged(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun isTagged( tag: Array, addressId: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == addressId - @JvmStatic fun isTagged( tag: Array, address: MeetingRoomTag, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == address.toTag() - @JvmStatic fun isIn( tag: Array, addressIds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in addressIds - @JvmStatic fun isTaggedWithKind( tag: Array, kind: String, ) = tag.has(1) && tag[0] == TAG_NAME && Address.isOfKind(tag[1], kind) - @JvmStatic fun parse( aTagId: String, relay: String?, @@ -81,7 +75,6 @@ class MeetingRoomTag( MeetingRoomTag(it, relay?.let { RelayUrlNormalizer.normalizeOrNull(it) }) } - @JvmStatic fun parse(tag: Array): MeetingRoomTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -89,7 +82,6 @@ class MeetingRoomTag( return parse(tag[1], tag.getOrNull(2)) } - @JvmStatic fun parseValidAddress(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -97,7 +89,6 @@ class MeetingRoomTag( return Address.parse(tag[1])?.toValue() } - @JvmStatic fun parseAddress(tag: Array): Address? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -105,7 +96,6 @@ class MeetingRoomTag( return Address.parse(tag[1]) } - @JvmStatic fun parseAddressId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -113,7 +103,6 @@ class MeetingRoomTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): AddressHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -127,19 +116,16 @@ class MeetingRoomTag( return AddressHint(tag[1], relayHint) } - @JvmStatic fun assemble( aTagId: HexKey, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, aTagId, relay?.url) - @JvmStatic fun assemble( address: Address, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, address.toValue(), relay?.url) - @JvmStatic fun assemble( kind: Int, pubKey: String, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/LiveActivitiesEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/LiveActivitiesEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/LiveActivitiesEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/LiveActivitiesEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/CurrentParticipantsTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/CurrentParticipantsTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/CurrentParticipantsTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/CurrentParticipantsTag.kt index 3891a7cad9..d6e9bd84a7 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/CurrentParticipantsTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/CurrentParticipantsTag.kt @@ -27,7 +27,6 @@ class CurrentParticipantsTag { companion object { const val TAG_NAME = "current_participants" - @JvmStatic fun parse(tag: Array): Int? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class CurrentParticipantsTag { return tag[1].toIntOrNull() } - @JvmStatic fun assemble(participantCount: Int) = arrayOf(TAG_NAME, participantCount.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/EndsTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/EndsTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/EndsTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/EndsTag.kt index ea7253cc80..2643bffc58 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/EndsTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/EndsTag.kt @@ -27,7 +27,6 @@ class EndsTag { companion object { const val TAG_NAME = "ends" - @JvmStatic fun parse(tag: Array): Long? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class EndsTag { return tag[1].toLongOrNull() } - @JvmStatic fun assemble(timestamp: Long) = arrayOf(TAG_NAME, timestamp.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/ParticipantTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/ParticipantTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/ParticipantTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/ParticipantTag.kt index c2f929f66e..8a4cfaf6b8 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/ParticipantTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/ParticipantTag.kt @@ -54,7 +54,6 @@ data class ParticipantTag( keys: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in keys - @JvmStatic fun isHost(tag: Tag): Boolean { ensure(tag.has(3)) { return false } ensure(tag[0] == TAG_NAME) { return false } @@ -63,7 +62,6 @@ data class ParticipantTag( return true } - @JvmStatic fun parse(tag: Tag): ParticipantTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -74,7 +72,6 @@ data class ParticipantTag( return ParticipantTag(tag[1], hint, tag.getOrNull(3), tag.getOrNull(4)) } - @JvmStatic fun parseHost(tag: Tag): ParticipantTag? { ensure(tag.has(3)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -86,7 +83,6 @@ data class ParticipantTag( return ParticipantTag(tag[1], hint, tag[3], tag.getOrNull(4)) } - @JvmStatic fun parseKey(tag: Tag): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -94,7 +90,6 @@ data class ParticipantTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): PubKeyHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -107,7 +102,6 @@ data class ParticipantTag( return PubKeyHint(tag[1], hint) } - @JvmStatic fun assemble( pubkey: HexKey, relayHint: String?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/PinnedEventTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/PinnedEventTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/PinnedEventTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/PinnedEventTag.kt index da9810bb26..1092292ab9 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/PinnedEventTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/PinnedEventTag.kt @@ -37,7 +37,6 @@ class PinnedEventTag { eventIds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in eventIds - @JvmStatic fun parse(tag: Tag): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -45,7 +44,6 @@ class PinnedEventTag { return tag[1] } - @JvmStatic fun assemble(eventId: HexKey) = arrayOfNotNull(TAG_NAME, eventId) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/RecordingTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/RecordingTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/RecordingTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/RecordingTag.kt index 7f4c6953b4..50c3d5e44f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/RecordingTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/RecordingTag.kt @@ -27,7 +27,6 @@ class RecordingTag { companion object { const val TAG_NAME = "recording" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class RecordingTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/RelayListTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/RelayListTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/RelayListTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/RelayListTag.kt index e158c766f8..5804540896 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/RelayListTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/RelayListTag.kt @@ -29,7 +29,6 @@ class RelayListTag { companion object { const val TAG_NAME = "relays" - @JvmStatic fun parse(tag: Array): List? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -44,7 +43,6 @@ class RelayListTag { return relays } - @JvmStatic fun assemble(urls: List) = arrayOf(TAG_NAME) + urls.map { it.url }.toTypedArray() } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StartsTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StartsTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StartsTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StartsTag.kt index e9007ac37e..f24c297d42 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StartsTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StartsTag.kt @@ -27,7 +27,6 @@ class StartsTag { companion object { const val TAG_NAME = "starts" - @JvmStatic fun parse(tag: Array): Long? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class StartsTag { return tag[1].toLongOrNull() } - @JvmStatic fun assemble(timestamp: Long) = arrayOf(TAG_NAME, timestamp.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StatusTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StatusTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StatusTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StatusTag.kt index 37f65ba403..e0cf843582 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StatusTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StatusTag.kt @@ -48,7 +48,6 @@ class StatusTag { companion object { const val TAG_NAME = "status" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -56,7 +55,6 @@ class StatusTag { return tag[1] } - @JvmStatic fun parseEnum(tag: Array): STATUS? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -64,7 +62,6 @@ class StatusTag { return STATUS.parse(tag[1]) } - @JvmStatic fun assemble(status: STATUS) = arrayOf(TAG_NAME, status.code) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StreamingTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StreamingTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StreamingTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StreamingTag.kt index 432e78a7ea..c9fca2dddd 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StreamingTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/StreamingTag.kt @@ -27,7 +27,6 @@ class StreamingTag { companion object { const val TAG_NAME = "streaming" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class StreamingTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/TotalParticipantsTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/TotalParticipantsTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/TotalParticipantsTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/TotalParticipantsTag.kt index 8a03816440..80f8f87ee9 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/TotalParticipantsTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip53LiveActivities/streaming/tags/TotalParticipantsTag.kt @@ -27,7 +27,6 @@ class TotalParticipantsTag { companion object { const val TAG_NAME = "total_participants" - @JvmStatic fun parse(tag: Array): Int? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class TotalParticipantsTag { return tag[1].toIntOrNull() } - @JvmStatic fun assemble(participantCount: Int) = arrayOf(TAG_NAME, participantCount.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt index a33a6c2ad1..ebc6d3a160 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip54Wiki/WikiNoteEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip54Wiki import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider @@ -31,9 +32,8 @@ import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.publishedAt.PublishedAtProvider @@ -47,7 +47,6 @@ import com.vitorpamplona.quartz.nip19Bech32.eventIds import com.vitorpamplona.quartz.nip19Bech32.pubKeyHints import com.vitorpamplona.quartz.nip19Bech32.pubKeys import com.vitorpamplona.quartz.nip23LongContent.tags.PublishedAtTag -import com.vitorpamplona.quartz.nip23LongContent.tags.PublishedAtTag.Companion.parse import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip50Search.SearchableEvent import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/ReportEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/ReportEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/ReportEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/ReportEvent.kt index 9b6f5a3637..f1f601c64f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/ReportEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/ReportEvent.kt @@ -42,7 +42,8 @@ class ReportEvent( content: String, sig: HexKey, ) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - @Transient + @kotlinx.serialization.Transient + @kotlin.jvm.Transient private var defaultType: ReportType? = null private fun defaultReportTypes() = tags.mapNotNull(DefaultReportTag::parse) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/ReportType.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/ReportType.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/ReportType.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/ReportType.kt index 018b5e5221..8c65370aba 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/ReportType.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/ReportType.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.quartz.nip56Reports -import android.util.Log +import com.vitorpamplona.quartz.utils.Log enum class ReportType( val code: String, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/TagArrayBuilderExt.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/TagArrayBuilderExt.kt index 55f621e878..9f332f496a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/TagArrayBuilderExt.kt @@ -20,9 +20,9 @@ */ package com.vitorpamplona.quartz.nip56Reports +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip56Reports.tags.HashSha256Tag import com.vitorpamplona.quartz.nip56Reports.tags.ReportedAddressTag import com.vitorpamplona.quartz.nip56Reports.tags.ReportedAuthorTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/BaseReportTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/BaseReportTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/BaseReportTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/BaseReportTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/DefaultReportTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/DefaultReportTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/DefaultReportTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/DefaultReportTag.kt index 94516387e7..2b46e40012 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/DefaultReportTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/DefaultReportTag.kt @@ -32,7 +32,6 @@ class DefaultReportTag { companion object { const val TAG_NAME = "report" - @JvmStatic fun parse(tag: Array): ReportType? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -41,7 +40,6 @@ class DefaultReportTag { return ReportType.parseOrNull(tag[1], tag) } - @JvmStatic fun assemble(type: ReportType? = null) = arrayOfNotNull(TAG_NAME, type?.code) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/HashSha256Tag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/HashSha256Tag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/HashSha256Tag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/HashSha256Tag.kt index 9d95975062..81ea550c8b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/HashSha256Tag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/HashSha256Tag.kt @@ -33,7 +33,6 @@ class HashSha256Tag( companion object { const val TAG_NAME = "x" - @JvmStatic fun parse( tag: Array, defaultReportType: ReportType? = null, @@ -46,7 +45,6 @@ class HashSha256Tag( return HashSha256Tag(tag[1], type) } - @JvmStatic fun assemble( hash: String, type: ReportType? = null, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedAddressTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedAddressTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedAddressTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedAddressTag.kt index a7bca9fe24..d822f57bca 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedAddressTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedAddressTag.kt @@ -21,8 +21,8 @@ package com.vitorpamplona.quartz.nip56Reports.tags import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.has -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip56Reports.ReportType import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.ensure @@ -37,7 +37,6 @@ class ReportedAddressTag( companion object { const val TAG_NAME = "a" - @JvmStatic fun parse( tag: Array, defaultReportType: ReportType? = null, @@ -62,7 +61,6 @@ class ReportedAddressTag( return ReportedAddressTag(address, type) } - @JvmStatic fun assemble( address: Address, type: ReportType? = null, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedAuthorTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedAuthorTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedAuthorTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedAuthorTag.kt index 23d7eeb293..2d153585e5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedAuthorTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedAuthorTag.kt @@ -37,7 +37,6 @@ class ReportedAuthorTag( companion object { const val TAG_NAME = "p" - @JvmStatic fun parse( tag: Array, defaultReportType: ReportType? = null, @@ -58,7 +57,6 @@ class ReportedAuthorTag( return ReportedAuthorTag(tag[1], type) } - @JvmStatic fun assemble( pubkey: HexKey, type: ReportType? = null, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedEventTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedEventTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedEventTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedEventTag.kt index 59fe9d0c0a..d6be6d8481 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedEventTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ReportedEventTag.kt @@ -37,7 +37,6 @@ class ReportedEventTag( companion object { const val TAG_NAME = "e" - @JvmStatic fun parse( tag: Array, defaultReportType: ReportType? = null, @@ -58,7 +57,6 @@ class ReportedEventTag( return ReportedEventTag(tag[1], type) } - @JvmStatic fun assemble( eventId: HexKey, type: ReportType? = null, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ServerTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ServerTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ServerTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ServerTag.kt index d1124ebc3d..d4e047d2dd 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ServerTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip56Reports/tags/ServerTag.kt @@ -27,17 +27,14 @@ class ServerTag { companion object { const val TAG_NAME = "server" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) - @JvmStatic fun assemble(urls: List) = urls.map { assemble(it) } } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapEvent.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapEvent.kt index bd7299f9f1..d6962b0311 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapEvent.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.quartz.nip57Zaps -import android.util.Log import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.experimental.zapPolls.tags.PollOptionTag import com.vitorpamplona.quartz.lightning.LnInvoiceUtil @@ -29,9 +28,10 @@ import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.pointerSizeInBytes @Immutable @@ -60,7 +60,9 @@ class LnZapEvent( override fun linkedAddressIds() = tags.mapNotNull(ATag::parseAddressId) // This event is also kept in LocalCache (same object) - @Transient val zapRequest: LnZapRequestEvent? + @kotlinx.serialization.Transient + @kotlin.jvm.Transient + val zapRequest: LnZapRequestEvent? // Keeps this as a field because it's a heavier function used everywhere. val amount by lazy { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapEventInterface.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapEventInterface.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapEventInterface.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapEventInterface.kt index 41c25adead..82122491fe 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapEventInterface.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapEventInterface.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.quartz.nip57Zaps import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.Event -import java.math.BigDecimal +import com.vitorpamplona.quartz.utils.BigDecimal @Immutable interface LnZapEventInterface { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapPrivateEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapPrivateEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapPrivateEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapPrivateEvent.kt index f2901533ee..cf0d1552fd 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapPrivateEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapPrivateEvent.kt @@ -28,7 +28,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt index e2768c4590..e900332e1b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/LnZapRequestEvent.kt @@ -32,7 +32,7 @@ import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip31Alts.AltTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapCache.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapCache.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapCache.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapEncryption.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapEncryption.kt similarity index 71% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapEncryption.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapEncryption.kt index f6704ccb65..89480352ad 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapEncryption.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapEncryption.kt @@ -22,13 +22,10 @@ package com.vitorpamplona.quartz.nip57Zaps import com.vitorpamplona.quartz.nip04Dm.crypto.Nip04 import com.vitorpamplona.quartz.nip19Bech32.bech32.Bech32 +import com.vitorpamplona.quartz.utils.RandomInstance +import com.vitorpamplona.quartz.utils.ciphers.AESCBC import com.vitorpamplona.quartz.utils.sha256.sha256 -import java.nio.charset.Charset -import java.security.SecureRandom -import javax.crypto.BadPaddingException -import javax.crypto.Cipher -import javax.crypto.spec.IvParameterSpec -import javax.crypto.spec.SecretKeySpec +import kotlinx.coroutines.CancellationException class PrivateZapEncryption { companion object { @@ -38,7 +35,7 @@ class PrivateZapEncryption { createdAt: Long, ): ByteArray { val str = privkey + id + createdAt.toString() - val strbyte = str.toByteArray(Charset.forName("utf-8")) + val strbyte = str.encodeToByteArray() return sha256(strbyte) } @@ -48,16 +45,12 @@ class PrivateZapEncryption { pubkey: ByteArray, ): String { val sharedSecret = Nip04.getSharedSecret(privkey, pubkey) - val iv = ByteArray(16) - SecureRandom().nextBytes(iv) + val iv = RandomInstance.bytes(16) - val keySpec = SecretKeySpec(sharedSecret, "AES") - val ivSpec = IvParameterSpec(iv) + val utf8message = msg.encodeToByteArray() - val utf8message = msg.toByteArray(Charset.forName("utf-8")) - val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") - cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec) - val encryptedMsg = cipher.doFinal(utf8message) + val cipher = AESCBC(sharedSecret, iv) + val encryptedMsg = cipher.encrypt(utf8message) val encryptedMsgBech32 = Bech32.encode("pzap", Bech32.eight2five(encryptedMsg), Bech32.Encoding.Bech32) @@ -82,20 +75,15 @@ class PrivateZapEncryption { val iv = parts[1].run { Bech32.decode(this).second } val encryptedMsg = parts.first().run { Bech32.decode(this).second } val encryptedBytes = Bech32.five2eight(encryptedMsg, 0) - val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") - cipher.init( - Cipher.DECRYPT_MODE, - SecretKeySpec(sharedSecret, "AES"), - IvParameterSpec( - Bech32.five2eight(iv, 0), - ), - ) + + val cipher = AESCBC(sharedSecret, Bech32.five2eight(iv, 0)) try { - val decryptedMsgBytes = cipher.doFinal(encryptedBytes) - return String(decryptedMsgBytes) - } catch (ex: BadPaddingException) { - throw IllegalArgumentException("Bad padding: ${ex.message}") + val decryptedMsgBytes = cipher.decrypt(encryptedBytes) + return decryptedMsgBytes.decodeToString() + } catch (e: Exception) { + if (e is CancellationException) throw e + throw IllegalArgumentException("Bad padding: ${e.message}") } } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapRequestBuilder.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapRequestBuilder.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapRequestBuilder.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/PrivateZapRequestBuilder.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/BaseZapSplitSetup.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/BaseZapSplitSetup.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/BaseZapSplitSetup.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/BaseZapSplitSetup.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetup.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetup.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetup.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetup.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupLnAddress.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupLnAddress.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupLnAddress.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupLnAddress.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupParser.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupParser.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupParser.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupParser.kt index 3924e101b9..1c2004f346 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupParser.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupParser.kt @@ -26,10 +26,8 @@ import com.vitorpamplona.quartz.utils.ensure class ZapSplitSetupParser { companion object { - @JvmStatic fun isTagged(tags: Array) = tags.has(1) && tags[0] == BaseZapSplitSetup.TAG_NAME - @JvmStatic fun parse(tags: Array): BaseZapSplitSetup? { ensure(tags.has(1)) { return null } ensure(tags[0] == BaseZapSplitSetup.TAG_NAME) { return null } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupSerializer.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupSerializer.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupSerializer.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupSerializer.kt index dbef78241f..8fdd9db9c4 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupSerializer.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/splits/ZapSplitSetupSerializer.kt @@ -24,7 +24,6 @@ import com.vitorpamplona.quartz.utils.arrayOfNotNull class ZapSplitSetupSerializer { companion object { - @JvmStatic fun toTagArray(zapSplit: BaseZapSplitSetup): Array = when (zapSplit) { is ZapSplitSetupLnAddress -> arrayOf(BaseZapSplitSetup.TAG_NAME, zapSplit.lnAddress) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/ZapRaiserTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/ZapRaiserTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/ZapRaiserTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/ZapRaiserTag.kt index a86d4215cc..a666a41e45 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/ZapRaiserTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip57Zaps/zapraiser/ZapRaiserTag.kt @@ -33,13 +33,11 @@ class ZapRaiserTag( companion object { const val TAG_NAME = "zapraiser" - @JvmStatic fun parse(tags: Array): ZapRaiserTag? { require(tags[0] == TAG_NAME) return tags[1].toLongOrNull()?.let { ZapRaiserTag(it) } } - @JvmStatic fun assemble(amountInSats: Long) = arrayOf(TAG_NAME, amountInSats.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeAwardEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeAwardEvent.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeAwardEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeAwardEvent.kt index 3f94a7c8f5..ec89c9dcdb 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeAwardEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeAwardEvent.kt @@ -26,8 +26,8 @@ import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.taggedAddresses +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.taggedAddresses import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.taggedUserIds diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeDefinitionEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeDefinitionEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeDefinitionEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeDefinitionEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeProfilesEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeProfilesEvent.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeProfilesEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeProfilesEvent.kt index 2e47fcbcb4..00514b7e86 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeProfilesEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip58Badges/BadgeProfilesEvent.kt @@ -21,14 +21,14 @@ package com.vitorpamplona.quartz.nip58Badges import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address -import com.vitorpamplona.quartz.nip01Core.tags.addressables.taggedAddresses +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.taggedAddresses import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents import com.vitorpamplona.quartz.nip01Core.tags.people.PTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/HostStub.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/HostStub.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/HostStub.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/HostStub.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/WrappedEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/WrappedEvent.kt similarity index 90% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/WrappedEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/WrappedEvent.kt index d7687bf21c..ea9b6fe9e7 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/WrappedEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/WrappedEvent.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.quartz.nip59Giftwrap import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey +import kotlinx.serialization.Transient @Immutable open class WrappedEvent( @@ -34,5 +35,7 @@ open class WrappedEvent( content: String, sig: HexKey, ) : Event(id, pubKey, createdAt, kind, tags, content, sig) { - @Transient var host: HostStub? = null // host event to broadcast when needed + @kotlinx.serialization.Transient + @kotlin.jvm.Transient + var host: HostStub? = null // host event to broadcast when needed } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/Rumor.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/Rumor.kt similarity index 83% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/Rumor.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/Rumor.kt index 02ad68890e..632e9f1b35 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/Rumor.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/Rumor.kt @@ -20,22 +20,22 @@ */ package com.vitorpamplona.quartz.nip59Giftwrap.rumors -import com.fasterxml.jackson.annotation.JsonProperty -import com.vitorpamplona.quartz.EventFactory import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper +import com.vitorpamplona.quartz.nip01Core.core.OptimizedSerializable import com.vitorpamplona.quartz.nip01Core.crypto.EventHasher -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent +import com.vitorpamplona.quartz.utils.EventFactory class Rumor( val id: HexKey?, - @field:JsonProperty("pubkey") val pubKey: HexKey?, - @field:JsonProperty("created_at") val createdAt: Long?, + val pubKey: HexKey?, + val createdAt: Long?, val kind: Int?, val tags: Array>?, val content: String?, -) { +) : OptimizedSerializable { fun mergeWith(event: SealedRumorEvent): Event { val newPubKey = event.pubKey // forces to be the pubkey of the seal to make sure impersonators don't impersonate val newCreatedAt = if (createdAt != null && createdAt > 1000) createdAt else event.createdAt @@ -49,9 +49,9 @@ class Rumor( } companion object { - fun fromJson(json: String): Rumor = JsonMapper.mapper.readValue(json, Rumor::class.java) + fun fromJson(json: String): Rumor = OptimizedJsonMapper.fromJsonTo(json) - fun toJson(event: Rumor): String = JsonMapper.mapper.writeValueAsString(event) + fun toJson(event: Rumor): String = OptimizedJsonMapper.toJson(event) fun create(event: Event): Rumor = Rumor(event.id, event.pubKey, event.createdAt, event.kind, event.tags, event.content) } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/RumorAssembler.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/RumorAssembler.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/RumorAssembler.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/RumorAssembler.kt index 65e7a61fc7..6d8d8760cd 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/RumorAssembler.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/RumorAssembler.kt @@ -20,11 +20,11 @@ */ package com.vitorpamplona.quartz.nip59Giftwrap.rumors -import com.vitorpamplona.quartz.EventFactory import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.crypto.EventHasher import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate +import com.vitorpamplona.quartz.utils.EventFactory class RumorAssembler { companion object { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/seals/SealedRumorEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/seals/SealedRumorEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/seals/SealedRumorEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/seals/SealedRumorEvent.kt index 210cc13f93..c8a06bde83 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/seals/SealedRumorEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/seals/SealedRumorEvent.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.quartz.nip59Giftwrap.seals -import android.util.Log import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey @@ -29,6 +28,7 @@ import com.vitorpamplona.quartz.nip40Expiration.ExpirationTag import com.vitorpamplona.quartz.nip59Giftwrap.HostStub import com.vitorpamplona.quartz.nip59Giftwrap.WrappedEvent import com.vitorpamplona.quartz.nip59Giftwrap.rumors.Rumor +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.pointerSizeInBytes @@ -42,7 +42,9 @@ class SealedRumorEvent( content: String, sig: HexKey, ) : WrappedEvent(id, pubKey, createdAt, KIND, tags, content, sig) { - @Transient var innerEventId: HexKey? = null + @kotlinx.serialization.Transient + @kotlin.jvm.Transient + var innerEventId: HexKey? = null override fun countMemory(): Int = super.countMemory() + diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/wraps/GiftWrapEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/wraps/GiftWrapEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/wraps/GiftWrapEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/wraps/GiftWrapEvent.kt index 8f2e65cf35..b408fd19b4 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/wraps/GiftWrapEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/wraps/GiftWrapEvent.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.quartz.nip59Giftwrap.wraps -import android.util.Log import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey @@ -33,6 +32,7 @@ import com.vitorpamplona.quartz.nip21UriScheme.toNostrUri import com.vitorpamplona.quartz.nip40Expiration.ExpirationTag import com.vitorpamplona.quartz.nip59Giftwrap.HostStub import com.vitorpamplona.quartz.nip59Giftwrap.WrappedEvent +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.pointerSizeInBytes @@ -46,7 +46,9 @@ class GiftWrapEvent( content: String, sig: HexKey, ) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - @Transient var innerEventId: HexKey? = null + @kotlinx.serialization.Transient + @kotlin.jvm.Transient + var innerEventId: HexKey? = null override fun countMemory(): Int = super.countMemory() + diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/RequestToVanishEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/RequestToVanishEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/RequestToVanishEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/RequestToVanishEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/RelayTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/RelayTag.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/RelayTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/RelayTag.kt index 18342f0f2a..297fc6aa80 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/RelayTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/RelayTag.kt @@ -28,19 +28,15 @@ class RelayTag { const val TAG_NAME = "relay" const val EVERYWHERE = "ALL_RELAYS" - @JvmStatic fun match(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun notMatch(tag: Array) = !(tag.has(0) && tag[0] == TAG_NAME) - @JvmStatic fun shouldVanishFrom( tag: Array, relayUrl: String?, ) = tag.has(1) && tag[0] == TAG_NAME && (tag[1] == relayUrl || tag[1] == EVERYWHERE) - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -48,7 +44,6 @@ class RelayTag { return tag[1] } - @JvmStatic fun assemble(relay: String) = arrayOf(TAG_NAME, relay) fun assembleEverywhere() = arrayOf(TAG_NAME, EVERYWHERE) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip62RequestToVanish/tags/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/AdvertisedRelayListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/AdvertisedRelayListEvent.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/AdvertisedRelayListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/AdvertisedRelayListEvent.kt index 8f1093b0fc..2edac4794b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/AdvertisedRelayListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/AdvertisedRelayListEvent.kt @@ -21,12 +21,12 @@ package com.vitorpamplona.quartz.nip65RelayList import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip65RelayList.tags.AdvertisedRelayInfo import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/RelayListRecommendationProcessor.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/RelayListRecommendationProcessor.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/RelayListRecommendationProcessor.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/RelayListRecommendationProcessor.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/tags/AdvertisedRelayInfoTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/tags/AdvertisedRelayInfoTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/tags/AdvertisedRelayInfoTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/tags/AdvertisedRelayInfoTag.kt index 57215a4431..1ecf00e477 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/tags/AdvertisedRelayInfoTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip65RelayList/tags/AdvertisedRelayInfoTag.kt @@ -40,7 +40,6 @@ class AdvertisedRelayInfo( fun notMatch(tag: Array) = !(tag.has(0) && tag[0] == TAG_NAME) - @JvmStatic fun parse(tag: Array): AdvertisedRelayInfo? { ensure(match(tag)) { return null } @@ -58,14 +57,12 @@ class AdvertisedRelayInfo( return AdvertisedRelayInfo(normalizedUrl, type) } - @JvmStatic fun parseNorm(tag: Array): NormalizedRelayUrl? { ensure(match(tag)) { return null } val normalizedUrl = RelayUrlNormalizer.normalizeOrNull(tag[1]) return normalizedUrl } - @JvmStatic fun parseRead(tag: Array): String? { ensure(match(tag)) { return null } ensure(AdvertisedRelayType.isRead(tag.getOrNull(2))) { return null } @@ -73,7 +70,6 @@ class AdvertisedRelayInfo( return tag[1] } - @JvmStatic fun parseWrite(tag: Array): String? { ensure(match(tag)) { return null } ensure(AdvertisedRelayType.isWrite(tag.getOrNull(2))) { return null } @@ -81,7 +77,6 @@ class AdvertisedRelayInfo( return tag[1] } - @JvmStatic fun parseReadNorm(tag: Array): NormalizedRelayUrl? { ensure(tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()) { return null } @@ -96,7 +91,6 @@ class AdvertisedRelayInfo( return RelayUrlNormalizer.normalizeOrNull(tag[1]) } - @JvmStatic fun parseWriteNorm(tag: Array): NormalizedRelayUrl? { ensure(tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()) { return null } @@ -111,7 +105,6 @@ class AdvertisedRelayInfo( return relay } - @JvmStatic fun assemble( relay: NormalizedRelayUrl, type: AdvertisedRelayType, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/IMetaTagBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/IMetaTagBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/IMetaTagBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/IMetaTagBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/IMetaTagExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/IMetaTagExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/IMetaTagExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/IMetaTagExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/PictureEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/PictureEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/PictureEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/PictureEvent.kt index 7315ecf396..1132557b39 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/PictureEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/PictureEvent.kt @@ -46,7 +46,9 @@ class PictureEvent( sig: HexKey, ) : Event(id, pubKey, createdAt, KIND, tags, content, sig), RootScope { - @Transient var iMetas: List? = null + @kotlinx.serialization.Transient + @kotlin.jvm.Transient + var iMetas: List? = null fun title() = tags.firstNotNullOfOrNull(TitleTag::parse) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/PictureMeta.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/PictureMeta.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/PictureMeta.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/PictureMeta.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/tags/LocationTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/tags/LocationTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/tags/LocationTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/tags/LocationTag.kt index a46e0e2ee1..5d2bac70e5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/tags/LocationTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/tags/LocationTag.kt @@ -27,7 +27,6 @@ class LocationTag { companion object { const val TAG_NAME = "location" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class LocationTag { return tag[1] } - @JvmStatic fun assemble(locationName: String) = arrayOf(TAG_NAME, locationName) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/tags/UserAnnotationTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/tags/UserAnnotationTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/tags/UserAnnotationTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/tags/UserAnnotationTag.kt index 69d2f1d19b..3d7f8b685c 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip68Picture/tags/UserAnnotationTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip68Picture/tags/UserAnnotationTag.kt @@ -32,7 +32,6 @@ class UserAnnotationTag( companion object { const val TAG_NAME = "annotate-user" - @JvmStatic fun parse(value: String): UserAnnotationTag? { val ann = value.split(":") if (ann.size == 3) { @@ -46,7 +45,6 @@ class UserAnnotationTag( return null } - @JvmStatic fun assemble(tag: UserAnnotationTag) = arrayOf(TAG_NAME, tag.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/tags/ProtectedTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/tags/ProtectedTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/tags/ProtectedTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/tags/ProtectedTag.kt index 8088d65064..14da5f4a65 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/tags/ProtectedTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip70ProtectedEvts/tags/ProtectedTag.kt @@ -28,21 +28,18 @@ class ProtectedTag { companion object { const val TAG_NAME = "-" - @JvmStatic fun match(tag: Tag): Boolean { ensure(tag.has(0)) { return false } ensure(tag[0] == TAG_NAME) { return false } return true } - @JvmStatic fun parse(tag: Tag): Boolean? { ensure(tag.has(0)) { return null } ensure(tag[0] == TAG_NAME) { return null } return true } - @JvmStatic fun assemble() = arrayOf(TAG_NAME) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/IMetaTagBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/IMetaTagBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/IMetaTagBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/IMetaTagBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/IMetaTagExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/IMetaTagExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/IMetaTagExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/IMetaTagExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/RegularVideoEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/RegularVideoEvent.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/RegularVideoEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/RegularVideoEvent.kt index 0007b48c1f..7aa603bfff 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/RegularVideoEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/RegularVideoEvent.kt @@ -49,7 +49,9 @@ abstract class RegularVideoEvent( PublishedAtProvider, VideoEvent, RootScope { - @Transient var iMetas: List? = null + @kotlinx.serialization.Transient + @kotlin.jvm.Transient + var iMetas: List? = null override fun title() = tags.firstNotNullOfOrNull(TitleTag::parse) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/ReplaceableVideoEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/ReplaceableVideoEvent.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/ReplaceableVideoEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/ReplaceableVideoEvent.kt index 645eb87a5d..6f99ed24fd 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/ReplaceableVideoEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/ReplaceableVideoEvent.kt @@ -49,7 +49,9 @@ abstract class ReplaceableVideoEvent( PublishedAtProvider, VideoEvent, RootScope { - @Transient var iMetas: List? = null + @kotlinx.serialization.Transient + @kotlin.jvm.Transient + var iMetas: List? = null override fun title() = tags.firstNotNullOfOrNull(TitleTag::parse) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoHorizontalEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoHorizontalEvent.kt similarity index 90% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoHorizontalEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoHorizontalEvent.kt index 39738bb911..6e536ea742 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoHorizontalEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoHorizontalEvent.kt @@ -24,14 +24,15 @@ import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip22Comments.RootScope import com.vitorpamplona.quartz.nip31Alts.alt -import com.vitorpamplona.quartz.nip71Video.videoIMetas import com.vitorpamplona.quartz.utils.TimeUtils -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable +@OptIn(ExperimentalUuidApi::class) class VideoHorizontalEvent( id: HexKey, pubKey: HexKey, @@ -48,7 +49,7 @@ class VideoHorizontalEvent( fun build( video: VideoMeta, description: String, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = build(description, dTag, createdAt) { @@ -59,7 +60,7 @@ class VideoHorizontalEvent( fun build( video: List, description: String, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = build(description, dTag, createdAt) { @@ -69,7 +70,7 @@ class VideoHorizontalEvent( fun build( description: String, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = eventTemplate(KIND, description, createdAt) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoMeta.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoMeta.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoMeta.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoMeta.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoNormalEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoNormalEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoNormalEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoNormalEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoShortEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoShortEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoShortEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoShortEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoVerticalEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoVerticalEvent.kt similarity index 90% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoVerticalEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoVerticalEvent.kt index 0751775fed..5230266698 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoVerticalEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/VideoVerticalEvent.kt @@ -24,13 +24,15 @@ import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip22Comments.RootScope import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.utils.TimeUtils -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable +@OptIn(ExperimentalUuidApi::class) class VideoVerticalEvent( id: HexKey, pubKey: HexKey, @@ -47,7 +49,7 @@ class VideoVerticalEvent( fun build( video: VideoMeta, description: String, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = build(description, dTag, createdAt) { @@ -57,7 +59,7 @@ class VideoVerticalEvent( fun build( description: String, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = eventTemplate(KIND, description, createdAt) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/DurationTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/DurationTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/DurationTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/DurationTag.kt index d2862f8abd..928b5762fd 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/DurationTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/DurationTag.kt @@ -27,7 +27,6 @@ class DurationTag { companion object { const val TAG_NAME = "duration" - @JvmStatic fun parse(tag: Array): Int? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class DurationTag { return tag[1].toIntOrNull() } - @JvmStatic fun assemble(durationInSeconds: Int) = arrayOf(TAG_NAME, durationInSeconds.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/SegmentTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/SegmentTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/SegmentTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/SegmentTag.kt index a4e00839e4..213277d617 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/SegmentTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/SegmentTag.kt @@ -37,7 +37,6 @@ class SegmentTag( companion object { const val TAG_NAME = "segment" - @JvmStatic fun parse(tag: Array): SegmentTag? { ensure(tag.has(3)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -47,7 +46,6 @@ class SegmentTag( return SegmentTag(tag[1], tag[2], tag[3], tag.getOrNull(4)) } - @JvmStatic fun assemble( // HH:MM:SS.sss start: String, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/TextTrackTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/TextTrackTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/TextTrackTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/TextTrackTag.kt index d1cd9cf236..5de8e7452b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/TextTrackTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip71Video/tags/TextTrackTag.kt @@ -41,7 +41,6 @@ data class TextTrackTag( companion object { const val TAG_NAME = "text-track" - @JvmStatic fun parse(tag: Array): TextTrackTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -49,7 +48,6 @@ data class TextTrackTag( return TextTrackTag(tag[1], tag.getOrNull(2)) } - @JvmStatic fun assemble( eventId: HexKey, relay: String?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/EventExt.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/EventExt.kt index 29fcd7c20d..584939eb3f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/EventExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/EventExt.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.quartz.nip72ModCommunities +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.any import com.vitorpamplona.quartz.nip01Core.core.fastFirstNotNullOfOrNull -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip22Comments.CommentEvent import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent import com.vitorpamplona.quartz.nip72ModCommunities.follow.tags.CommunityTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/CommunityPostApprovalEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/CommunityPostApprovalEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/CommunityPostApprovalEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/CommunityPostApprovalEvent.kt index c92515154e..3fe6c21612 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/CommunityPostApprovalEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/CommunityPostApprovalEvent.kt @@ -20,8 +20,8 @@ */ package com.vitorpamplona.quartz.nip72ModCommunities.approval -import android.util.Log import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder @@ -31,7 +31,6 @@ import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip01Core.tags.kinds.kind import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip31Alts.alt @@ -39,6 +38,7 @@ import com.vitorpamplona.quartz.nip72ModCommunities.approval.tags.ApprovedAddres import com.vitorpamplona.quartz.nip72ModCommunities.approval.tags.ApprovedEventTag import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent import com.vitorpamplona.quartz.nip72ModCommunities.follow.tags.CommunityTag +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils @Immutable diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/TagArrayBuilderExt.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/TagArrayBuilderExt.kt index 870bd9df68..fd750e2681 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/TagArrayBuilderExt.kt @@ -24,6 +24,8 @@ import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle +import com.vitorpamplona.quartz.nip01Core.tags.aTag.toATag +import com.vitorpamplona.quartz.nip01Core.tags.events.toETagArray import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent fun TagArrayBuilder.community(event: EventHintBundle) = add(event.toATag().toATagArray()) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/tags/ApprovedAddressTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/tags/ApprovedAddressTag.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/tags/ApprovedAddressTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/tags/ApprovedAddressTag.kt index 1e2a4582f4..f0b8051833 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/tags/ApprovedAddressTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/tags/ApprovedAddressTag.kt @@ -20,12 +20,12 @@ */ package com.vitorpamplona.quartz.nip72ModCommunities.approval.tags +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.bytesUsedInMemory @@ -47,28 +47,23 @@ class ApprovedAddressTag( companion object { const val TAG_NAME = "a" - @JvmStatic fun isTagged(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && !Address.isOfKind(tag[1], CommunityDefinitionEvent.KIND_STR) - @JvmStatic fun isTagged( tag: Array, addressId: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == addressId - @JvmStatic fun isTagged( tag: Array, address: ApprovedAddressTag, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == address.toTag() - @JvmStatic fun isIn( tag: Array, addressIds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in addressIds - @JvmStatic fun parse(tag: Array): ApprovedAddressTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -79,7 +74,6 @@ class ApprovedAddressTag( return ApprovedAddressTag(address, relayHint) } - @JvmStatic fun parseValidAddress(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -87,7 +81,6 @@ class ApprovedAddressTag( return Address.parse(tag[1])?.toValue() } - @JvmStatic fun parseAddress(tag: Array): Address? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -97,7 +90,6 @@ class ApprovedAddressTag( return address } - @JvmStatic fun parseAddressId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -105,7 +97,6 @@ class ApprovedAddressTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): AddressHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -119,19 +110,16 @@ class ApprovedAddressTag( return AddressHint(tag[1], relayHint) } - @JvmStatic fun assemble( aTagId: HexKey, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, aTagId, relay?.url) - @JvmStatic fun assemble( address: Address, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, address.toValue(), relay?.url) - @JvmStatic fun assemble( kind: Int, pubKey: String, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/tags/ApprovedEventTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/tags/ApprovedEventTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/tags/ApprovedEventTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/tags/ApprovedEventTag.kt index 94e8d04bfc..1856de1418 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/tags/ApprovedEventTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/approval/tags/ApprovedEventTag.kt @@ -43,22 +43,18 @@ class ApprovedEventTag( companion object { const val TAG_NAME = "e" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun isTagged( tag: Array, eventId: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == eventId - @JvmStatic fun isIn( tag: Array, eventIds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in eventIds - @JvmStatic fun parse(tag: Array): ApprovedEventTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -66,7 +62,6 @@ class ApprovedEventTag( return ApprovedEventTag(tag[1], tag.getOrNull(2)?.let { RelayUrlNormalizer.normalizeOrNull(it) }, tag.getOrNull(3)) } - @JvmStatic fun parseId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -74,7 +69,6 @@ class ApprovedEventTag( return tag[1] } - @JvmStatic fun parseValidId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -83,7 +77,6 @@ class ApprovedEventTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): EventIdHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -96,14 +89,12 @@ class ApprovedEventTag( return EventIdHint(tag[1], relayHint) } - @JvmStatic fun assemble( eventId: HexKey, relay: NormalizedRelayUrl?, pubkey: String?, ) = arrayOfNotNull(TAG_NAME, eventId, relay?.url, pubkey) - @JvmStatic fun assemble(ref: EventReference) = assemble(ref.eventId, ref.relayHint, ref.author) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/CommunityDefinitionEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/CommunityDefinitionEvent.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/CommunityDefinitionEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/CommunityDefinitionEvent.kt index b0cee2d875..82ad704bb3 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/CommunityDefinitionEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/CommunityDefinitionEvent.kt @@ -29,8 +29,8 @@ import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip18Reposts.quotes.QTag import com.vitorpamplona.quartz.nip31Alts.alt @@ -41,7 +41,8 @@ import com.vitorpamplona.quartz.nip72ModCommunities.definition.tags.NameTag import com.vitorpamplona.quartz.nip72ModCommunities.definition.tags.RelayTag import com.vitorpamplona.quartz.nip72ModCommunities.definition.tags.RulesTag import com.vitorpamplona.quartz.utils.TimeUtils -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable class CommunityDefinitionEvent( @@ -91,6 +92,7 @@ class CommunityDefinitionEvent( const val KIND_STR = "34550" const val ALT_DESCRIPTION = "Community definition" + @OptIn(ExperimentalUuidApi::class) fun build( name: String, description: String, @@ -98,7 +100,7 @@ class CommunityDefinitionEvent( image: String? = null, rules: String? = null, relays: List? = null, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = eventTemplate(KIND, "", createdAt) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/DescriptionTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/DescriptionTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/DescriptionTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/DescriptionTag.kt index 107c5ea787..1b9d8b2e18 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/DescriptionTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/DescriptionTag.kt @@ -27,7 +27,6 @@ class DescriptionTag { companion object { const val TAG_NAME = "description" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class DescriptionTag { return tag[1] } - @JvmStatic fun assemble(title: String) = arrayOf(TAG_NAME, title) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/ImageTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/ImageTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/ImageTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/ImageTag.kt index 5c1fc2a650..974d95277f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/ImageTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/ImageTag.kt @@ -32,7 +32,6 @@ class ImageTag( companion object { const val TAG_NAME = "image" - @JvmStatic fun parse(tag: Array): ImageTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -41,7 +40,6 @@ class ImageTag( return ImageTag(tag[1], dims) } - @JvmStatic fun assemble( imageUrl: String, dimensions: DimensionTag? = null, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/ModeratorTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/ModeratorTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/ModeratorTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/ModeratorTag.kt index 2bccc47901..d0aba35242 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/ModeratorTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/ModeratorTag.kt @@ -42,7 +42,6 @@ data class ModeratorTag( companion object { const val TAG_NAME = "p" - @JvmStatic fun parse(tag: Tag): ModeratorTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -53,7 +52,6 @@ data class ModeratorTag( return ModeratorTag(tag[1], hint, tag.getOrNull(3)) } - @JvmStatic fun parseKey(tag: Tag): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -61,7 +59,6 @@ data class ModeratorTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): PubKeyHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -74,7 +71,6 @@ data class ModeratorTag( return PubKeyHint(tag[1], hint) } - @JvmStatic fun assemble( pubkey: HexKey, relayHint: NormalizedRelayUrl?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/NameTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/NameTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/NameTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/NameTag.kt index 91fba35934..7866c65f57 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/NameTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/NameTag.kt @@ -27,7 +27,6 @@ class NameTag { companion object { const val TAG_NAME = "name" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class NameTag { return tag[1] } - @JvmStatic fun assemble(name: String) = arrayOf(TAG_NAME, name) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/RelayTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/RelayTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/RelayTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/RelayTag.kt index 09e62790d6..8dff4f4420 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/RelayTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/RelayTag.kt @@ -35,7 +35,6 @@ class RelayTag( companion object { const val TAG_NAME = "relay" - @JvmStatic fun parse(tag: Array): RelayTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -46,7 +45,6 @@ class RelayTag( return RelayTag(relay, tag.getOrNull(2)) } - @JvmStatic fun parseUrls(tag: Array): NormalizedRelayUrl? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -57,7 +55,6 @@ class RelayTag( return relay } - @JvmStatic fun assemble( relay: NormalizedRelayUrl, marker: String? = null, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/RulesTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/RulesTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/RulesTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/RulesTag.kt index 2db22f6daa..e7b9de6709 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/RulesTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/definition/tags/RulesTag.kt @@ -27,7 +27,6 @@ class RulesTag { companion object { const val TAG_NAME = "rules" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class RulesTag { return tag[1] } - @JvmStatic fun assemble(rules: String) = arrayOf(TAG_NAME, rules) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/CommunityListEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/CommunityListEvent.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/CommunityListEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/CommunityListEvent.kt index 8628b3fceb..b3bf6668c5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/CommunityListEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/CommunityListEvent.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip72ModCommunities.follow import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArray import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder @@ -29,7 +30,6 @@ import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip51Lists.PrivateTagArrayEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/TagArrayBuilderExt.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/TagArrayBuilderExt.kt index af274d9efc..fefb73faa9 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/TagArrayBuilderExt.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.quartz.nip72ModCommunities.follow +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip51Lists.tags.NameTag import com.vitorpamplona.quartz.nip72ModCommunities.follow.tags.CommunityTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/tags/CommunityTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/tags/CommunityTag.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/tags/CommunityTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/tags/CommunityTag.kt index 262d201e22..fcdaba6ec8 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/tags/CommunityTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip72ModCommunities/follow/tags/CommunityTag.kt @@ -20,12 +20,12 @@ */ package com.vitorpamplona.quartz.nip72ModCommunities.follow.tags +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.bytesUsedInMemory @@ -47,34 +47,28 @@ class CommunityTag( companion object { const val TAG_NAME = "a" - @JvmStatic fun isTagged(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && Address.isOfKind(tag[1], CommunityDefinitionEvent.KIND_STR) - @JvmStatic fun isTagged( tag: Array, addressId: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == addressId - @JvmStatic fun isTagged( tag: Array, address: CommunityTag, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == address.toTag() - @JvmStatic fun isTaggedWithKind( tag: Array, kind: String, ) = tag.has(1) && tag[0] == TAG_NAME && Address.isOfKind(tag[1], kind) - @JvmStatic fun isIn( tag: Array, addressIds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in addressIds - @JvmStatic fun parse(tag: Array): CommunityTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -85,7 +79,6 @@ class CommunityTag( return CommunityTag(address, relayHint) } - @JvmStatic fun parseValidAddress(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -93,7 +86,6 @@ class CommunityTag( return Address.parse(tag[1])?.toValue() } - @JvmStatic fun parseAddress(tag: Array): Address? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -103,7 +95,6 @@ class CommunityTag( return address } - @JvmStatic fun parseAddressId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -111,7 +102,6 @@ class CommunityTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): AddressHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -124,19 +114,16 @@ class CommunityTag( return AddressHint(tag[1], relayHint) } - @JvmStatic fun assemble( aTagId: HexKey, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, aTagId, relay?.url) - @JvmStatic fun assemble( address: Address, relay: NormalizedRelayUrl?, ) = arrayOfNotNull(TAG_NAME, address.toValue(), relay?.url) - @JvmStatic fun assemble( kind: Int, pubKey: String, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/CommentEventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/CommentEventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/CommentEventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/CommentEventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/ExternalId.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/ExternalId.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/ExternalId.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/ExternalId.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/books/BookId.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/books/BookId.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/books/BookId.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/books/BookId.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/books/CommentEventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/books/CommentEventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/books/CommentEventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/books/CommentEventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/location/CommentEventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/location/CommentEventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/location/CommentEventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/location/CommentEventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/location/GeohashId.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/location/GeohashId.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/location/GeohashId.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/location/GeohashId.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/movies/CommentEventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/movies/CommentEventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/movies/CommentEventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/movies/CommentEventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/movies/MovieId.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/movies/MovieId.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/movies/MovieId.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/movies/MovieId.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/papers/CommentEventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/papers/CommentEventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/papers/CommentEventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/papers/CommentEventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/papers/PaperId.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/papers/PaperId.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/papers/PaperId.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/papers/PaperId.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/CommentEventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/CommentEventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/CommentEventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/CommentEventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastEpisodeId.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastEpisodeId.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastEpisodeId.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastEpisodeId.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastFeedId.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastFeedId.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastFeedId.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastFeedId.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastPublisherId.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastPublisherId.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastPublisherId.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/podcasts/PodcastPublisherId.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/topics/CommentEventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/topics/CommentEventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/topics/CommentEventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/topics/CommentEventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/topics/HashtagId.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/topics/HashtagId.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/topics/HashtagId.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/topics/HashtagId.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/urls/CommentEventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/urls/CommentEventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/urls/CommentEventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/urls/CommentEventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/urls/UrlId.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/urls/UrlId.kt similarity index 92% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/urls/UrlId.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/urls/UrlId.kt index 9b51ac7856..87676399d8 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/urls/UrlId.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip73ExternalIds/urls/UrlId.kt @@ -21,9 +21,8 @@ package com.vitorpamplona.quartz.nip73ExternalIds.urls import com.vitorpamplona.quartz.nip73ExternalIds.ExternalId +import com.vitorpamplona.quartz.utils.Rfc3986 import com.vitorpamplona.quartz.utils.ensure -import com.vitorpamplona.quartz.utils.toStringNoFragment -import org.czeal.rfc3986.URIReference class UrlId( val url: String, @@ -40,7 +39,7 @@ class UrlId( const val PREFIX1 = "https://" const val PREFIX2 = "http://" - fun toScope(url: String) = URIReference.parse(url).normalize().toStringNoFragment() + fun toScope(url: String) = Rfc3986.normalizeAndRemoveFragment(url) fun toKind(url: String) = KIND diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/GoalEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/GoalEvent.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/GoalEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/GoalEvent.kt index 293ecde409..be03fd2575 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/GoalEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/GoalEvent.kt @@ -31,8 +31,10 @@ import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.toATag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag +import com.vitorpamplona.quartz.nip01Core.tags.events.toETag import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.references.reference diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/TagArrayBuilderExt.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/TagArrayBuilderExt.kt index 8d9595d3b3..8a3222b593 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/TagArrayBuilderExt.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.quartz.nip75ZapGoals import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip23LongContent.tags.ImageTag import com.vitorpamplona.quartz.nip23LongContent.tags.SummaryTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/AmountTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/AmountTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/AmountTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/AmountTag.kt index d20fd89934..6eef07466c 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/AmountTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/AmountTag.kt @@ -27,7 +27,6 @@ class AmountTag { companion object { const val TAG_NAME = "amount" - @JvmStatic fun parse(tag: Array): Long? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class AmountTag { return tag[1].toLongOrNull() } - @JvmStatic fun assemble(amountInMillisats: Long) = arrayOf(TAG_NAME, amountInMillisats.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/ClosedAtTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/ClosedAtTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/ClosedAtTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/ClosedAtTag.kt index 2f3c4efcab..e82a8c5bdf 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/ClosedAtTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/ClosedAtTag.kt @@ -27,7 +27,6 @@ class ClosedAtTag { companion object { const val TAG_NAME = "closed_at" - @JvmStatic fun parse(tag: Array): Long? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class ClosedAtTag { return tag[1].toLongOrNull() } - @JvmStatic fun assemble(timestamp: Long) = arrayOf(TAG_NAME, timestamp.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/RelayListTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/RelayListTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/RelayListTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/RelayListTag.kt index da4c72540d..3de5fad9f6 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/RelayListTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip75ZapGoals/tags/RelayListTag.kt @@ -29,7 +29,6 @@ class RelayListTag( companion object { const val TAG_NAME = "relays" - @JvmStatic fun parse(tag: Array): RelayListTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -41,10 +40,8 @@ class RelayListTag( return RelayListTag(relays) } - @JvmStatic fun assemble(urls: List) = arrayOf(TAG_NAME) + urls.toTypedArray() - @JvmStatic fun assemble(tag: RelayListTag) = assemble(tag.relayUrls) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip78AppData/AppSpecificDataEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip78AppData/AppSpecificDataEvent.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip78AppData/AppSpecificDataEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip78AppData/AppSpecificDataEvent.kt index 6dcd9a31eb..f5b34919f2 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip78AppData/AppSpecificDataEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip78AppData/AppSpecificDataEvent.kt @@ -20,11 +20,11 @@ */ package com.vitorpamplona.quartz.nip78AppData +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/HighlightEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/HighlightEvent.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/HighlightEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/HighlightEvent.kt index b1be670b95..d6c198a647 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/HighlightEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/HighlightEvent.kt @@ -29,9 +29,9 @@ import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.firstTaggedATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.firstTaggedAddress +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.firstTaggedATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.firstTaggedAddress import com.vitorpamplona.quartz.nip01Core.tags.events.ETag import com.vitorpamplona.quartz.nip01Core.tags.events.firstTaggedEvent import com.vitorpamplona.quartz.nip01Core.tags.people.PTag diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/tags/CommentTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/tags/CommentTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/tags/CommentTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/tags/CommentTag.kt index 63598db3de..6b5ccbc414 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/tags/CommentTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/tags/CommentTag.kt @@ -27,7 +27,6 @@ class CommentTag { companion object { const val TAG_NAME = "comment" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class CommentTag { return tag[1] } - @JvmStatic fun assemble(context: String) = arrayOf(TAG_NAME, context) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/tags/ContextTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/tags/ContextTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/tags/ContextTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/tags/ContextTag.kt index 5468c1976d..82ce001bc1 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/tags/ContextTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip84Highlights/tags/ContextTag.kt @@ -27,7 +27,6 @@ class ContextTag { companion object { const val TAG_NAME = "context" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class ContextTag { return tag[1] } - @JvmStatic fun assemble(context: String) = arrayOf(TAG_NAME, context) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/PlatformType.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/PlatformType.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/PlatformType.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/PlatformType.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/ClientTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/ClientTag.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/ClientTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/ClientTag.kt index 2810fe19ef..a6c88f820b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/ClientTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/ClientTag.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.quartz.nip89AppHandlers.clientTag +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip46RemoteSigner.getOrNull import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.ensure @@ -38,10 +38,8 @@ class ClientTag( companion object { const val TAG_NAME = "client" - @JvmStatic fun isTag(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun parse(tag: Array): ClientTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -57,17 +55,14 @@ class ClientTag( ) } - @JvmStatic fun assemble(name: String) = arrayOfNotNull(TAG_NAME, name) - @JvmStatic fun assemble( name: String, address: String? = null, relayHint: NormalizedRelayUrl? = null, ) = arrayOfNotNull(TAG_NAME, name, address, relayHint?.url) - @JvmStatic fun assemble( name: String, address: Address? = null, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/clientTag/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppDefinitionEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppDefinitionEvent.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppDefinitionEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppDefinitionEvent.kt index b025dc79ab..a7706ff6e3 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppDefinitionEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppDefinitionEvent.kt @@ -20,13 +20,12 @@ */ package com.vitorpamplona.quartz.nip89AppHandlers.definition -import android.util.Log import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip01Core.tags.kinds.isTaggedKind import com.vitorpamplona.quartz.nip01Core.tags.kinds.kinds import com.vitorpamplona.quartz.nip01Core.tags.publishedAt.PublishedAtProvider @@ -35,11 +34,14 @@ import com.vitorpamplona.quartz.nip23LongContent.tags.PublishedAtTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip89AppHandlers.PlatformType import com.vitorpamplona.quartz.nip89AppHandlers.definition.tags.PlatformLinkTag +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.CancellationException -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable +@OptIn(ExperimentalUuidApi::class) class AppDefinitionEvent( id: HexKey, pubKey: HexKey, @@ -51,7 +53,9 @@ class AppDefinitionEvent( PublishedAtProvider { override fun countMemory(): Int = super.countMemory() + (cachedMetadata?.countMemory() ?: 8) - @Transient private var cachedMetadata: AppMetadata? = null + @kotlinx.serialization.Transient + @kotlin.jvm.Transient + private var cachedMetadata: AppMetadata? = null fun appMetaData() = if (cachedMetadata != null) { @@ -70,7 +74,7 @@ class AppDefinitionEvent( } } catch (e: Exception) { if (e is CancellationException) throw e - Log.w("AppDefinitionEvent", "Content Parse Error: ${toNostrUri()} ${e.localizedMessage}", e) + Log.w("AppDefinitionEvent", "Content Parse Error: ${toNostrUri()} ${e.message}", e) null } } @@ -111,7 +115,7 @@ class AppDefinitionEvent( details: AppMetadata, supportedKinds: Set, links: List, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = eventTemplate(KIND, details.toJson(), createdAt) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppMetadata.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppMetadata.kt similarity index 91% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppMetadata.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppMetadata.kt index f47606412f..d2cd247e80 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppMetadata.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/AppMetadata.kt @@ -21,17 +21,20 @@ package com.vitorpamplona.quartz.nip89AppHandlers.definition import androidx.compose.runtime.Stable -import com.fasterxml.jackson.annotation.JsonProperty -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.core.JsonMapper +import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppMetadata import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.pointerSizeInBytes +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable @Stable +@Serializable class AppMetadata { var name: String? = null var username: String? = null - @JsonProperty("display_name") + @SerialName("display_name") var displayName: String? = null var picture: String? = null @@ -113,8 +116,8 @@ class AppMetadata { fun toJson() = assemble(this) companion object { - fun assemble(data: AppMetadata): String = JsonMapper.mapper.writeValueAsString(data) + fun assemble(data: AppMetadata): String = JsonMapper.toJson(data) - fun parse(content: String): AppMetadata = JsonMapper.mapper.readValue(content, AppMetadata::class.java) + fun parse(content: String): AppMetadata = JsonMapper.fromJson(content) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/EntityType.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/EntityType.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/EntityType.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/EntityType.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/tags/PlatformLinkTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/tags/PlatformLinkTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/tags/PlatformLinkTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/tags/PlatformLinkTag.kt index d2278feef3..dbdddb7940 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/tags/PlatformLinkTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/definition/tags/PlatformLinkTag.kt @@ -33,7 +33,6 @@ class PlatformLinkTag( fun toTagArray() = assemble(platform, uri, entityType) companion object { - @JvmStatic fun match(tag: Tag): Boolean = if (tag.has(2)) { tag[0] == PlatformType.IOS.code || tag[0] == PlatformType.WEB.code || tag[0] == PlatformType.ANDROID.code @@ -41,13 +40,11 @@ class PlatformLinkTag( false } - @JvmStatic fun parse(tag: Tag): PlatformLinkTag? { if (match(tag)) return PlatformLinkTag(tag[1], tag[2], tag.getOrNull(3)) return null } - @JvmStatic fun assemble( platform: String, uri: String, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/AppRecommendationEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/AppRecommendationEvent.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/AppRecommendationEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/AppRecommendationEvent.kt index 04291e4dfa..56bee9d414 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/AppRecommendationEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/AppRecommendationEvent.kt @@ -27,7 +27,7 @@ import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip89AppHandlers.PlatformType import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/TagArrayBuilderExt.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/TagArrayBuilderExt.kt index 96122fd363..0447a97f1a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/TagArrayBuilderExt.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/TagArrayBuilderExt.kt @@ -20,9 +20,9 @@ */ package com.vitorpamplona.quartz.nip89AppHandlers.recommendation +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address import com.vitorpamplona.quartz.nip89AppHandlers.recommendation.tags.RecommendationTag fun TagArrayBuilder.recommend( diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/tags/RecommendationTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/tags/RecommendationTag.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/tags/RecommendationTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/tags/RecommendationTag.kt index 4056e736eb..e112c5e9a9 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/tags/RecommendationTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip89AppHandlers/recommendation/tags/RecommendationTag.kt @@ -21,13 +21,13 @@ package com.vitorpamplona.quartz.nip89AppHandlers.recommendation.tags import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.Tag import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.utils.arrayOfNotNull import com.vitorpamplona.quartz.utils.ensure @@ -42,10 +42,8 @@ class RecommendationTag( companion object { const val TAG_NAME = "a" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun parse(tag: Array): RecommendationTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -55,7 +53,6 @@ class RecommendationTag( return RecommendationTag(address, relayHint, tag.getOrNull(3)) } - @JvmStatic fun parseAddressId(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -63,7 +60,6 @@ class RecommendationTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): AddressHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == ATag.Companion.TAG_NAME) { return null } @@ -76,14 +72,12 @@ class RecommendationTag( return AddressHint(tag[1], relayHint) } - @JvmStatic fun assemble( addressId: String, relay: NormalizedRelayUrl?, platform: String?, ) = arrayOfNotNull(TAG_NAME, addressId, relay?.url, platform) - @JvmStatic fun assemble( address: Address, relay: NormalizedRelayUrl?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90ContentDiscoveryRequestEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90ContentDiscoveryRequestEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90ContentDiscoveryRequestEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90ContentDiscoveryRequestEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90ContentDiscoveryResponseEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90ContentDiscoveryResponseEvent.kt similarity index 90% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90ContentDiscoveryResponseEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90ContentDiscoveryResponseEvent.kt index ea94b7466b..516cd049a9 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90ContentDiscoveryResponseEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90ContentDiscoveryResponseEvent.kt @@ -20,17 +20,17 @@ */ package com.vitorpamplona.quartz.nip90Dvms -import android.util.Log import androidx.compose.runtime.Immutable -import com.fasterxml.jackson.module.kotlin.readValue import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip31Alts.AltTag +import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.bytesUsedInMemory import com.vitorpamplona.quartz.utils.pointerSizeInBytes +import kotlinx.serialization.Transient @Immutable class NIP90ContentDiscoveryResponseEvent( @@ -41,7 +41,9 @@ class NIP90ContentDiscoveryResponseEvent( content: String, sig: HexKey, ) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - @Transient var events: List? = null + @kotlinx.serialization.Transient + @kotlin.jvm.Transient + var events: List? = null override fun countMemory(): Int = super.countMemory() + @@ -58,7 +60,7 @@ class NIP90ContentDiscoveryResponseEvent( try { events = - JsonMapper.mapper.readValue>>(content).mapNotNull { + OptimizedJsonMapper.fromJsonToTagArray(content).mapNotNull { if (it.size > 1 && it[0] == "e") { it[1] } else { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90StatusEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90StatusEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90StatusEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90StatusEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90UserDiscoveryRequestEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90UserDiscoveryRequestEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90UserDiscoveryRequestEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90UserDiscoveryRequestEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90UserDiscoveryResponseEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90UserDiscoveryResponseEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90UserDiscoveryResponseEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip90Dvms/NIP90UserDiscoveryResponseEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/EventExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/EventExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/EventExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/EventExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/IMetaTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/IMetaTag.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/IMetaTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/IMetaTag.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/IMetaTagBuilder.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/IMetaTagBuilder.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/IMetaTagBuilder.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/IMetaTagBuilder.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/TagArrayExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/TagArrayExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/TagArrayExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip92IMeta/TagArrayExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/FileHeaderEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/FileHeaderEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/FileHeaderEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/FileHeaderEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/IMetaTagBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/IMetaTagBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/IMetaTagBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/IMetaTagBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/BlurhashTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/BlurhashTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/BlurhashTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/BlurhashTag.kt index 427a52f031..5562144a3c 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/BlurhashTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/BlurhashTag.kt @@ -27,7 +27,6 @@ class BlurhashTag { companion object { const val TAG_NAME = "blurhash" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class BlurhashTag { return tag[1] } - @JvmStatic fun assemble(hash: String) = arrayOf(TAG_NAME, hash) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/DimensionTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/DimensionTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/DimensionTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/DimensionTag.kt index 3c393950e4..c5fc2131e8 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/DimensionTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/DimensionTag.kt @@ -22,7 +22,9 @@ package com.vitorpamplona.quartz.nip94FileMetadata.tags import com.vitorpamplona.quartz.nip01Core.core.has import com.vitorpamplona.quartz.utils.ensure +import kotlinx.serialization.Serializable +@Serializable class DimensionTag( val width: Int, val height: Int, @@ -38,7 +40,6 @@ class DimensionTag( companion object { const val TAG_NAME = "dim" - @JvmStatic fun parse(tag: Array): DimensionTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -46,7 +47,6 @@ class DimensionTag( return parse(tag[1]) } - @JvmStatic fun parse(dim: String): DimensionTag? { if (dim == "0x0") return null @@ -63,7 +63,6 @@ class DimensionTag( } } - @JvmStatic fun assemble(dim: DimensionTag) = arrayOf(TAG_NAME, dim.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/FallbackTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/FallbackTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/FallbackTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/FallbackTag.kt index 153faa5e54..0d6d2c030b 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/FallbackTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/FallbackTag.kt @@ -27,7 +27,6 @@ class FallbackTag { companion object { const val TAG_NAME = "fallback" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class FallbackTag { return tag[1] } - @JvmStatic fun assemble(imageUrl: String) = arrayOf(TAG_NAME, imageUrl) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/HashSha256Tag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/HashSha256Tag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/HashSha256Tag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/HashSha256Tag.kt index 263ff5abb9..816420f696 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/HashSha256Tag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/HashSha256Tag.kt @@ -27,7 +27,6 @@ class HashSha256Tag { companion object { const val TAG_NAME = "x" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class HashSha256Tag { return tag[1] } - @JvmStatic fun assemble(hash: String) = arrayOf(TAG_NAME, hash) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ImageTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ImageTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ImageTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ImageTag.kt index fe55ccab79..d5909007af 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ImageTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ImageTag.kt @@ -32,7 +32,6 @@ class ImageTag( companion object { const val TAG_NAME = "image" - @JvmStatic fun parse(tag: Array): ImageTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -40,7 +39,6 @@ class ImageTag( return ImageTag(tag[1], tag.getOrNull(2)) } - @JvmStatic fun assemble( imageUrl: String, hash: String? = null, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/MagnetTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/MagnetTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/MagnetTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/MagnetTag.kt index 3f0ae6d8a8..9ad86abe32 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/MagnetTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/MagnetTag.kt @@ -27,7 +27,6 @@ class MagnetTag { companion object { const val TAG_NAME = "magnet" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class MagnetTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/MimeTypeTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/MimeTypeTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/MimeTypeTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/MimeTypeTag.kt index 6c6bd7deb1..5c6c4780b6 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/MimeTypeTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/MimeTypeTag.kt @@ -32,7 +32,6 @@ class MimeTypeTag { mimeTypes: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in mimeTypes - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -40,7 +39,6 @@ class MimeTypeTag { return tag[1] } - @JvmStatic fun assemble(mimeType: String) = arrayOf(TAG_NAME, mimeType) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/OriginalHashTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/OriginalHashTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/OriginalHashTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/OriginalHashTag.kt index cf07ae1f31..365903e540 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/OriginalHashTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/OriginalHashTag.kt @@ -27,7 +27,6 @@ class OriginalHashTag { companion object { const val TAG_NAME = "ox" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class OriginalHashTag { return tag[1] } - @JvmStatic fun assemble(hash: String) = arrayOf(TAG_NAME, hash) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ServiceTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ServiceTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ServiceTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ServiceTag.kt index 2c7188b0b5..dde397272e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ServiceTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ServiceTag.kt @@ -27,10 +27,8 @@ class ServiceTag { companion object { const val TAG_NAME = "service" - @JvmStatic fun isTag(tag: Array) = tag.has(0) && tag[0] == TAG_NAME - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -38,7 +36,6 @@ class ServiceTag { return tag[1] } - @JvmStatic fun assemble(serviceType: String) = arrayOf(TAG_NAME, serviceType) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/SizeTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/SizeTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/SizeTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/SizeTag.kt index cda211d95d..68b87575f2 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/SizeTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/SizeTag.kt @@ -27,7 +27,6 @@ class SizeTag { companion object { const val TAG_NAME = "size" - @JvmStatic fun parse(tag: Array): Int? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class SizeTag { return tag[1].toIntOrNull() } - @JvmStatic fun assemble(sizeInBytes: Int) = arrayOf(TAG_NAME, sizeInBytes.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/SummaryTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/SummaryTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/SummaryTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/SummaryTag.kt index 6a30162c47..b5a32e0bb4 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/SummaryTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/SummaryTag.kt @@ -27,10 +27,8 @@ class SummaryTag { companion object { const val TAG_NAME = "summary" - @JvmStatic fun isTag(tag: Array) = tag.has(1) && tag[0] == TAG_NAME - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -38,7 +36,6 @@ class SummaryTag { return tag[1] } - @JvmStatic fun assemble(excerpt: String) = arrayOf(TAG_NAME, excerpt) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ThumbTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ThumbTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ThumbTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ThumbTag.kt index 315357aaaf..9612fda08f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ThumbTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/ThumbTag.kt @@ -32,7 +32,6 @@ class ThumbTag( companion object { const val TAG_NAME = "thumb" - @JvmStatic fun parse(tag: Array): ThumbTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -40,7 +39,6 @@ class ThumbTag( return ThumbTag(tag[1], tag.getOrNull(2)) } - @JvmStatic fun assemble( imageUrl: String, hash: String? = null, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/TorrentInfoHash.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/TorrentInfoHash.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/TorrentInfoHash.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/TorrentInfoHash.kt index 8109846741..9523f51017 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/TorrentInfoHash.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/TorrentInfoHash.kt @@ -27,7 +27,6 @@ class TorrentInfoHash { companion object { const val TAG_NAME = "i" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class TorrentInfoHash { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/UrlTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/UrlTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/UrlTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/UrlTag.kt index 0b103f8196..833b69272d 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/UrlTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip94FileMetadata/tags/UrlTag.kt @@ -27,10 +27,8 @@ class UrlTag { companion object { const val TAG_NAME = "url" - @JvmStatic fun isTag(tag: Array) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -38,7 +36,6 @@ class UrlTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/actions/DeleteResult.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/actions/DeleteResult.kt similarity index 75% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/actions/DeleteResult.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/actions/DeleteResult.kt index 501772b59d..b01ffb9694 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/actions/DeleteResult.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/actions/DeleteResult.kt @@ -20,17 +20,10 @@ */ package com.vitorpamplona.quartz.nip96FileStorage.actions -import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import kotlinx.serialization.Serializable +@Serializable data class DeleteResult( val status: String?, val message: String?, -) { - companion object { - fun parse(body: String): DeleteResult { - val mapper = jacksonObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - return mapper.readValue(body, DeleteResult::class.java) - } - } -} +) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/actions/UploadResult.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/actions/UploadResult.kt similarity index 69% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/actions/UploadResult.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/actions/UploadResult.kt index a4b2d218b7..7db4ed4ccd 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/actions/UploadResult.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/actions/UploadResult.kt @@ -20,25 +20,19 @@ */ package com.vitorpamplona.quartz.nip96FileStorage.actions -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +@Serializable data class UploadResult( val status: String? = null, val message: String? = null, - @field:JsonProperty("processing_url") val processingUrl: String? = null, + @SerialName("processing_url") val processingUrl: String? = null, val percentage: Int? = null, - @field:JsonProperty("nip94_event") val nip94Event: PartialEvent? = null, -) { - companion object { - fun parse(body: String): UploadResult { - val mapper = jacksonObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - return mapper.readValue(body, UploadResult::class.java) - } - } -} + @SerialName("nip94_event") val nip94Event: PartialEvent? = null, +) +@Serializable class PartialEvent( val tags: Array>? = null, val content: String? = null, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/FileServersEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/FileServersEvent.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/FileServersEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/FileServersEvent.kt index fabcfb31b6..6fc73885f6 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/FileServersEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/FileServersEvent.kt @@ -21,12 +21,12 @@ package com.vitorpamplona.quartz.nip96FileStorage.config import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.nip96FileStorage.config.tags.ServerTag import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/tags/ServerTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/tags/ServerTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/tags/ServerTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/tags/ServerTag.kt index 46df00386b..508a3cb632 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/tags/ServerTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/config/tags/ServerTag.kt @@ -29,7 +29,6 @@ class ServerTag { fun isTag(tag: Array) = tag[0] == TAG_NAME - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -37,10 +36,8 @@ class ServerTag { return tag[1] } - @JvmStatic fun assemble(url: String) = arrayOf(TAG_NAME, url) - @JvmStatic fun assemble(urls: List) = urls.map { assemble(it) } } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfo.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfo.kt similarity index 54% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfo.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfo.kt index 7d773bf5c4..94abffca2d 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfo.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfo.kt @@ -20,27 +20,30 @@ */ package com.vitorpamplona.quartz.nip96FileStorage.info -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable typealias PlanName = String typealias MimeType = String +@Serializable data class ServerInfo( - @field:JsonProperty("api_url") val apiUrl: String, - @field:JsonProperty("download_url") val downloadUrl: String? = null, - @field:JsonProperty("delegated_to_url") val delegatedToUrl: String? = null, - @field:JsonProperty("supported_nips") val supportedNips: ArrayList = arrayListOf(), - @field:JsonProperty("tos_url") val tosUrl: String? = null, - @field:JsonProperty("content_types") val contentTypes: ArrayList = arrayListOf(), - @field:JsonProperty("plans") val plans: Map = mapOf(), + @SerialName("api_url") val apiUrl: String, + @SerialName("download_url") val downloadUrl: String? = null, + @SerialName("delegated_to_url") val delegatedToUrl: String? = null, + @SerialName("supported_nips") val supportedNips: ArrayList = arrayListOf(), + @SerialName("tos_url") val tosUrl: String? = null, + @SerialName("content_types") val contentTypes: ArrayList = arrayListOf(), + @SerialName("plans") val plans: Map = mapOf(), ) +@Serializable data class Plan( - @field:JsonProperty("name") val name: String? = null, - @field:JsonProperty("is_nip98_required") val isNip98Required: Boolean? = null, - @field:JsonProperty("url") val url: String? = null, - @field:JsonProperty("max_byte_size") val maxByteSize: Long? = null, - @field:JsonProperty("file_expiration") val fileExpiration: ArrayList = arrayListOf(), - @field:JsonProperty("media_transformations") val mediaTransformations: Map> = emptyMap(), + @SerialName("name") val name: String? = null, + @SerialName("is_nip98_required") val isNip98Required: Boolean? = null, + @SerialName("url") val url: String? = null, + @SerialName("max_byte_size") val maxByteSize: Long? = null, + @SerialName("file_expiration") val fileExpiration: ArrayList = arrayListOf(), + @SerialName("media_transformations") val mediaTransformations: Map> = emptyMap(), ) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.kt similarity index 71% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.kt index d98b191826..1faad75013 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.kt @@ -20,10 +20,7 @@ */ package com.vitorpamplona.quartz.nip96FileStorage.info -import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import java.net.URI -import java.net.URL +import kotlinx.serialization.json.Json class ServerInfoParser { fun assembleUrl(apiUrl: String): String = apiUrl.removeSuffix("/") + "/.well-known/nostr/nip96.json" @@ -32,9 +29,7 @@ class ServerInfoParser { baseUrl: String, body: String, ): ServerInfo { - val mapper = - jacksonObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - val serverInfo = mapper.readValue(body, ServerInfo::class.java) + val serverInfo = Json.decodeFromString(body) return serverInfo.copy( apiUrl = makeAbsoluteIfRelativeUrl(baseUrl, serverInfo.apiUrl), @@ -49,19 +44,9 @@ class ServerInfoParser { }, ) } - - fun makeAbsoluteIfRelativeUrl( - baseUrl: String, - potentialyRelativeUrl: String, - ): String = - try { - val apiUrl = URI(potentialyRelativeUrl) - if (apiUrl.isAbsolute) { - potentialyRelativeUrl - } else { - URL(URL(baseUrl), potentialyRelativeUrl).toString() - } - } catch (e: Exception) { - potentialyRelativeUrl - } } + +expect fun makeAbsoluteIfRelativeUrl( + baseUrl: String, + potentiallyRelativeUrl: String, +): String diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/HTTPAuthorizationEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/HTTPAuthorizationEvent.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/HTTPAuthorizationEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/HTTPAuthorizationEvent.kt index 6fa477c6d1..b0de03e413 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/HTTPAuthorizationEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/HTTPAuthorizationEvent.kt @@ -29,7 +29,7 @@ import com.vitorpamplona.quartz.nip98HttpAuth.tags.MethodTag import com.vitorpamplona.quartz.nip98HttpAuth.tags.PayloadHashTag import com.vitorpamplona.quartz.nip98HttpAuth.tags.UrlTag import com.vitorpamplona.quartz.utils.TimeUtils -import java.util.Base64 +import kotlin.io.encoding.Base64 @Immutable class HTTPAuthorizationEvent( @@ -46,7 +46,7 @@ class HTTPAuthorizationEvent( fun url() = tags.firstNotNullOfOrNull(UrlTag::parse) - fun rawToken() = Base64.getEncoder().encodeToString(toJson().toByteArray()) + fun rawToken() = Base64.encode(toJson().encodeToByteArray()) fun toAuthToken() = "Nostr ${rawToken()}" diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/MethodTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/MethodTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/MethodTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/MethodTag.kt index 4a18238972..073b081156 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/MethodTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/MethodTag.kt @@ -27,7 +27,6 @@ class MethodTag { companion object { const val TAG_NAME = "method" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class MethodTag { return tag[1] } - @JvmStatic fun assemble(title: String) = arrayOf(TAG_NAME, title) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/PayloadHashTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/PayloadHashTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/PayloadHashTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/PayloadHashTag.kt index 3f391eadcc..569d65464d 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/PayloadHashTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/PayloadHashTag.kt @@ -30,7 +30,6 @@ class PayloadHashTag { companion object { const val TAG_NAME = "payload" - @JvmStatic fun parse(tag: Array): HexKey? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -38,10 +37,8 @@ class PayloadHashTag { return tag[1] } - @JvmStatic fun assemble(hash: HexKey) = arrayOf(TAG_NAME, hash) - @JvmStatic fun assemble(payload: ByteArray) = assemble(sha256(payload).toHexKey()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/UrlTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/UrlTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/UrlTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/UrlTag.kt index e60fdedcf1..729411138e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/UrlTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip98HttpAuth/tags/UrlTag.kt @@ -27,7 +27,6 @@ class UrlTag { companion object { const val TAG_NAME = "u" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class UrlTag { return tag[1] } - @JvmStatic fun assemble(title: String) = arrayOf(TAG_NAME, title) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/ClassifiedsEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/ClassifiedsEvent.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/ClassifiedsEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/ClassifiedsEvent.kt index 6e80ba713c..8657de53f1 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/ClassifiedsEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/ClassifiedsEvent.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.core.containsAllTagNamesWithValues import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags import com.vitorpamplona.quartz.nip01Core.tags.publishedAt.PublishedAtProvider import com.vitorpamplona.quartz.nip23LongContent.tags.ImageTag @@ -40,7 +40,8 @@ import com.vitorpamplona.quartz.nip99Classifieds.tags.LocationTag import com.vitorpamplona.quartz.nip99Classifieds.tags.PriceTag import com.vitorpamplona.quartz.nip99Classifieds.tags.StatusTag import com.vitorpamplona.quartz.utils.TimeUtils -import java.util.UUID +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable class ClassifiedsEvent( @@ -91,10 +92,10 @@ class ClassifiedsEvent( val images = images() val imetas = imetas() - val imetaSet = imetas.associate { it.url to it } + val imetaSet = imetas.associateBy { it.url } return images.map { - val imeta = imetaSet.get(it) + val imeta = imetaSet[it] if (imeta != null) { ProductImageMeta.parse(imeta) } else { @@ -109,6 +110,7 @@ class ClassifiedsEvent( val REQUIRED_FIELDS = setOf(TitleTag.TAG_NAME, PriceTag.TAG_NAME, ImageTag.TAG_NAME) + @OptIn(ExperimentalUuidApi::class) fun build( title: String, price: PriceTag, @@ -117,7 +119,7 @@ class ClassifiedsEvent( condition: ConditionTag.CONDITION? = null, images: List? = null, status: StatusTag.STATUS = StatusTag.STATUS.ACTIVE, - dTag: String = UUID.randomUUID().toString(), + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), initializer: TagArrayBuilder.() -> Unit = {}, ) = eventTemplate(KIND, description, createdAt) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/ProductImageMeta.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/ProductImageMeta.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/ProductImageMeta.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/ProductImageMeta.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/ConditionTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/ConditionTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/ConditionTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/ConditionTag.kt index 357adc7c8e..0954b51ae3 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/ConditionTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/ConditionTag.kt @@ -43,7 +43,6 @@ class ConditionTag { companion object { const val TAG_NAME = "condition" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -51,10 +50,8 @@ class ConditionTag { return tag[1] } - @JvmStatic fun parseCondition(tag: Array): CONDITION? = parse(tag)?.let { CONDITION.parse(it) } - @JvmStatic fun assemble(condition: CONDITION) = arrayOf(TAG_NAME, condition.code) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/LocationTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/LocationTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/LocationTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/LocationTag.kt index 0bc4fedeba..5ca763fd93 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/LocationTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/LocationTag.kt @@ -27,7 +27,6 @@ class LocationTag { companion object { const val TAG_NAME = "location" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class LocationTag { return tag[1] } - @JvmStatic fun assemble(locationName: String) = arrayOf(TAG_NAME, locationName) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/PriceTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/PriceTag.kt similarity index 98% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/PriceTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/PriceTag.kt index fb9f5319b6..4d0464f7cb 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/PriceTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/PriceTag.kt @@ -34,7 +34,6 @@ data class PriceTag( companion object { const val TAG_NAME = "price" - @JvmStatic fun parse(tag: Array): PriceTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -42,7 +41,6 @@ data class PriceTag( return PriceTag(tag[1], tag.getOrNull(2), tag.getOrNull(3)) } - @JvmStatic fun assemble( amount: String, currency: String?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/StatusTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/StatusTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/StatusTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/StatusTag.kt index bdaf07682b..a21a4505e9 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/StatusTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip99Classifieds/tags/StatusTag.kt @@ -37,7 +37,6 @@ class StatusTag { companion object { const val TAG_NAME = "status" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -45,7 +44,6 @@ class StatusTag { return tag[1] } - @JvmStatic fun assemble(status: STATUS) = arrayOf(TAG_NAME, status.value) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/AudioMeta.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/AudioMeta.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/AudioMeta.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/AudioMeta.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/BaseVoiceEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/BaseVoiceEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/BaseVoiceEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/BaseVoiceEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/IMetaTagBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/IMetaTagBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/IMetaTagBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/IMetaTagBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/IMetaTagExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/IMetaTagExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/IMetaTagExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/IMetaTagExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/TagArrayBuilderExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/TagArrayBuilderExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/TagArrayBuilderExt.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/VoiceEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/VoiceEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/VoiceEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/VoiceEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/VoiceReplyEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/VoiceReplyEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/VoiceReplyEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/VoiceReplyEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/DurationTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/DurationTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/DurationTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/DurationTag.kt index af56d81f2d..0a7b8d477f 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/DurationTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/DurationTag.kt @@ -27,7 +27,6 @@ class DurationTag { companion object { const val TAG_NAME = "duration" - @JvmStatic fun parse(tag: Array): Int? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class DurationTag { return tag[1].toIntOrNull() } - @JvmStatic fun assemble(seconds: Int) = arrayOf(TAG_NAME, seconds.toString()) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/HashSha256Tag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/HashSha256Tag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/HashSha256Tag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/HashSha256Tag.kt index 9f42b8ad7f..c1dbfd41f6 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/HashSha256Tag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/HashSha256Tag.kt @@ -27,7 +27,6 @@ class HashSha256Tag { companion object { const val TAG_NAME = "sha256" - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -35,7 +34,6 @@ class HashSha256Tag { return tag[1] } - @JvmStatic fun assemble(hash: String) = arrayOf(TAG_NAME, hash) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/MimeTypeTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/MimeTypeTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/MimeTypeTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/MimeTypeTag.kt index 2dc30e0397..a0610004d5 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/MimeTypeTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/MimeTypeTag.kt @@ -32,7 +32,6 @@ class MimeTypeTag { mimeTypes: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in mimeTypes - @JvmStatic fun parse(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -40,7 +39,6 @@ class MimeTypeTag { return tag[1] } - @JvmStatic fun assemble(mimeType: String) = arrayOf(TAG_NAME, mimeType) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyAuthorTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyAuthorTag.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyAuthorTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyAuthorTag.kt index 5853f5f7ef..2352f42f7a 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyAuthorTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyAuthorTag.kt @@ -41,10 +41,8 @@ data class ReplyAuthorTag( companion object { const val TAG_NAME = "p" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun parse(tag: Tag): ReplyAuthorTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -55,7 +53,6 @@ data class ReplyAuthorTag( return ReplyAuthorTag(tag[1], hint) } - @JvmStatic fun parseKey(tag: Tag): HexKey? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -63,7 +60,6 @@ data class ReplyAuthorTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): PubKeyHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -76,7 +72,6 @@ data class ReplyAuthorTag( return PubKeyHint(tag[1], hint) } - @JvmStatic fun assemble( pubkey: HexKey, relayHint: NormalizedRelayUrl?, diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyEventTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyEventTag.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyEventTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyEventTag.kt index 08c10fd9fa..3c24cc17f9 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyEventTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyEventTag.kt @@ -43,22 +43,18 @@ class ReplyEventTag( companion object { const val TAG_NAME = "e" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun isTagged( tag: Array, eventId: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == eventId - @JvmStatic fun isIn( tag: Array, eventIds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in eventIds - @JvmStatic fun parse(tag: Array): ReplyEventTag? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -66,7 +62,6 @@ class ReplyEventTag( return ReplyEventTag(tag[1], tag.getOrNull(2)?.let { RelayUrlNormalizer.normalizeOrNull(it) }, tag.getOrNull(3)) } - @JvmStatic fun parseKey(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -74,7 +69,6 @@ class ReplyEventTag( return tag[1] } - @JvmStatic fun parseValidKey(tag: Array): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -83,7 +77,6 @@ class ReplyEventTag( return tag[1] } - @JvmStatic fun parseAsHint(tag: Array): EventIdHint? { ensure(tag.has(2)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -96,14 +89,12 @@ class ReplyEventTag( return EventIdHint(tag[1], relayHint) } - @JvmStatic fun assemble( eventId: HexKey, relay: NormalizedRelayUrl?, pubkey: String?, ) = arrayOfNotNull(TAG_NAME, eventId, relay?.url, pubkey) - @JvmStatic fun assemble(ref: EventReference) = assemble(ref.eventId, ref.relayHint, ref.author) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyKindTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyKindTag.kt similarity index 93% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyKindTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyKindTag.kt index 7ecb255b7f..0b3e2fa3a7 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyKindTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/ReplyKindTag.kt @@ -29,28 +29,23 @@ class ReplyKindTag { companion object { const val TAG_NAME = "k" - @JvmStatic fun match(tag: Tag) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty() - @JvmStatic fun isKind( tag: Tag, kind: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == kind - @JvmStatic fun isTagged( tag: Tag, kind: String, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == kind - @JvmStatic fun isIn( tag: Tag, kinds: Set, ) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in kinds - @JvmStatic fun parse(tag: Tag): String? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -58,19 +53,14 @@ class ReplyKindTag { return tag[1] } - @JvmStatic fun assemble(kind: String) = arrayOf(TAG_NAME, kind) - @JvmStatic fun assemble(kind: Int) = arrayOf(TAG_NAME, kind.toString()) - @JvmStatic fun assemble(id: ExternalId) = assemble(id.toKind()) - @JvmStatic fun assemble(kinds: List): List = kinds.map { assemble(it) } - @JvmStatic fun assemble(kinds: Set): List = kinds.map { assemble(it) } } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/WaveformTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/WaveformTag.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/WaveformTag.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/WaveformTag.kt index fc80d1829d..7c56c4a529 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/WaveformTag.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipA0VoiceMessages/tags/WaveformTag.kt @@ -31,10 +31,8 @@ class WaveformTag( companion object { const val TAG_NAME = "waveform" - @JvmStatic fun parse(tag: Array): WaveformTag? = parseWave(tag)?.let { WaveformTag(it) } - @JvmStatic fun parseWave(tag: Array): List? { ensure(tag.has(1)) { return null } ensure(tag[0] == TAG_NAME) { return null } @@ -51,16 +49,12 @@ class WaveformTag( return wave } - @JvmStatic fun assembleWaveInt(wave: List) = wave.joinToString(" ") - @JvmStatic fun assembleInt(wave: List) = arrayOf(TAG_NAME, assembleWaveInt(wave)) - @JvmStatic fun assembleWaveFloat(wave: List) = wave.joinToString(" ") - @JvmStatic fun assembleFloat(wave: List) = arrayOf(TAG_NAME, assembleWaveFloat(wave)) } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomAuthorizationEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomAuthorizationEvent.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomAuthorizationEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomAuthorizationEvent.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomServersEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomServersEvent.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomServersEvent.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomServersEvent.kt index 9e2c125702..bbdaef7eef 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomServersEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomServersEvent.kt @@ -21,11 +21,11 @@ package com.vitorpamplona.quartz.nipB7Blossom import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip31Alts.AltTag import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomUploadResult.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomUploadResult.kt new file mode 100644 index 0000000000..b03168a6ba --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipB7Blossom/BlossomUploadResult.kt @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2025 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.quartz.nipB7Blossom + +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import kotlinx.serialization.Serializable + +@Serializable +data class BlossomUploadResult( + // A publicly accessible URL to the BUD-01 GET / endpoint (optionally with a file extension) + val url: String?, + // The sha256 hash of the blob + val sha256: HexKey? = null, + // The size of the blob in bytes + val size: Long? = null, + // (optional) The MIME type of the blob + val type: String? = null, + // upload time + val uploaded: Long? = null, + // magnet link + val magnet: String? = null, + // info hash + val infohash: String? = null, + // ipfs link + val ipfs: String? = null, +) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/ArrayUtils.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ArrayUtils.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/ArrayUtils.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ArrayUtils.kt diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimal.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimal.kt new file mode 100644 index 0000000000..abe3e727d3 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimal.kt @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +expect class BigDecimal { + constructor(strVal: String) + constructor(doubleVal: Double) + constructor(intVal: Int) + constructor(longVal: Long) + + fun add(augend: BigDecimal): BigDecimal + + fun subtract(subtrahend: BigDecimal): BigDecimal + + fun multiply(multiplicand: BigDecimal): BigDecimal + + fun divide(divisor: BigDecimal): BigDecimal + + fun negate(): BigDecimal + + fun signum(): Int +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Hmac512.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BitSet.kt similarity index 82% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Hmac512.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BitSet.kt index c40a8767a4..e2c629ddc6 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Hmac512.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BitSet.kt @@ -20,14 +20,18 @@ */ package com.vitorpamplona.quartz.utils -import javax.crypto.Mac -import javax.crypto.spec.SecretKeySpec +expect class BitSet { + constructor(nBits: Int) -fun hmac512( - key: ByteArray, - data: ByteArray, -): ByteArray { - val mac = Mac.getInstance("HmacSHA512") - mac.init(SecretKeySpec(key, "HmacSHA512")) - return mac.doFinal(data) + fun set(bitIndex: Int) + + fun clear(bitIndex: Int) + + fun get(bitIndex: Int): Boolean + + fun size(): Int + + fun toByteArray(): ByteArray } + +expect fun bitSetValueOf(bytes: ByteArray): BitSet diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ByteArrayOutputStream.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ByteArrayOutputStream.kt new file mode 100644 index 0000000000..066961fef8 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ByteArrayOutputStream.kt @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +/** + * Converted from java.io.ByteArrayOutputStream + */ +class ByteArrayOutputStream( + size: Int = 32, +) { + var buf: ByteArray = ByteArray(size) + var count: Int = 0 + + private fun ensureCapacity(minCapacity: Int) { + if (minCapacity - buf.size > 0) { + grow(minCapacity) + } + } + + private fun grow(minCapacity: Int) { + val oldCapacity = buf.size + var newCapacity = oldCapacity shl 1 + if (newCapacity - minCapacity < 0) newCapacity = minCapacity + if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity) + + buf = buf.copyOf(newCapacity) + } + + fun write(b: Byte) { + ensureCapacity(count + 1) + buf[count] = b + count += 1 + } + + fun write( + b: ByteArray, + off: Int, + len: Int, + ) { + if ((off or len) < 0 || len > b.size - off) { + throw IllegalArgumentException("Invalid input bounds") + } + + ensureCapacity(count + len) + b.copyInto(buf, count, off, off + len) + count += len + } + + fun write(b: ByteArray) { + ensureCapacity(count + b.size) + b.copyInto(buf, count, 0, b.size) + count += b.size + } + + fun reset() { + count = 0 + } + + fun toByteArray(): ByteArray = buf.copyOf(count) + + fun size(): Int = count + + override fun toString(): String = buf.decodeToString(0, count) + + companion object { + private val MAX_ARRAY_SIZE: Int = Int.MAX_VALUE - 8 + + private fun hugeCapacity(minCapacity: Int): Int { + // overflow + if (minCapacity < 0) throw RuntimeException("Buffer overflow new size $minCapacity") + return if (minCapacity > MAX_ARRAY_SIZE) Int.MAX_VALUE else MAX_ARRAY_SIZE + } + } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Ensure.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Ensure.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Ensure.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Ensure.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/EventFactory.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/EventFactory.kt similarity index 99% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/EventFactory.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/EventFactory.kt index 54e6f80a1d..5b6fee5a89 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/EventFactory.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/EventFactory.kt @@ -18,7 +18,7 @@ * 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.quartz +package com.vitorpamplona.quartz.utils import com.vitorpamplona.quartz.experimental.audio.header.AudioHeaderEvent import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/GZip.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/GZip.kt new file mode 100644 index 0000000000..a6e109eb4b --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/GZip.kt @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +expect object GZip { + fun compress(content: String): ByteArray + + fun decompress(content: ByteArray): String +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Hex.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Hex.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Hex.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Hex.kt index 0ff6eec22e..4882f15fc0 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/Hex.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Hex.kt @@ -36,7 +36,6 @@ object Hex { (LOWER_CASE_HEX[(it shr 4)].code shl 8) or LOWER_CASE_HEX[(it and 0xF)].code } - @JvmStatic fun isHex(hex: String?): Boolean { if (hex.isNullOrEmpty()) return false if (hex.length and 1 != 0) return false @@ -46,7 +45,7 @@ object Hex { if (c < 0 || c > 255) return false if (hexToByte[hex[c].code] < 0) return false } - } catch (e: IllegalArgumentException) { + } catch (_: IllegalArgumentException) { // there are p tags with emoji's which makes the hex[c].code > 256 return false } @@ -54,7 +53,6 @@ object Hex { return true } - @JvmStatic fun decode(hex: String): ByteArray { // faster version of hex decoder require(hex.length and 1 == 0) @@ -63,7 +61,6 @@ object Hex { } } - @JvmStatic fun encode(input: ByteArray): String { val out = CharArray(input.size * 2) var outIdx = 0 @@ -72,7 +69,7 @@ object Hex { out[outIdx++] = (chars shr 8).toChar() out[outIdx++] = (chars and 0xFF).toChar() } - return String(out) + return out.concatToString() } fun isEqual( diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/IterableExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/IterableExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/IterableExt.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/IterableExt.kt diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/JsonElementExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/JsonElementExt.kt new file mode 100644 index 0000000000..b9ee7f61ce --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/JsonElementExt.kt @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.jsonPrimitive + +public val JsonElement.text: String + get() = jsonPrimitive.content diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.kt new file mode 100644 index 0000000000..f6da0be7a7 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.kt @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +expect object LibSodiumInstance { + fun cryptoAeadXChaCha20Poly1305IetfDecrypt( + message: ByteArray, + nSec: ByteArray, + ciphertext: ByteArray, + ad: ByteArray, + nPub: ByteArray, + k: ByteArray, + ): Boolean + + fun cryptoAeadXChaCha20Poly1305IetfEncrypt( + ciphertext: ByteArray, + message: ByteArray, + ad: ByteArray, + nSec: ByteArray, + nPub: ByteArray, + k: ByteArray, + ): Boolean + + fun cryptoStreamChaCha20IetfXor( + message: ByteArray, + nonce: ByteArray?, + key: ByteArray?, + ): ByteArray + + // This function wasn't available in the bindings library. I had to move them here from C + fun cryptoStreamXChaCha20Xor( + messageBytes: ByteArray, + nonce: ByteArray, + key: ByteArray, + ): ByteArray +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Log.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Log.kt new file mode 100644 index 0000000000..518a3c6f34 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Log.kt @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +expect object Log { + fun w( + tag: String, + message: String, + throwable: Throwable? = null, + ) + + fun e( + tag: String, + message: String, + throwable: Throwable? = null, + ) + + fun d( + tag: String, + message: String, + ) + + fun i( + tag: String, + message: String, + ) +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/MapOfSetBuilder.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/MapOfSetBuilder.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/MapOfSetBuilder.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/MapOfSetBuilder.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/ParallelUtils.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ParallelUtils.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/ParallelUtils.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ParallelUtils.kt diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/Platform.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Platform.kt similarity index 93% rename from quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/Platform.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Platform.kt index efd8e787c1..ae2b90cc74 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/Platform.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Platform.kt @@ -18,6 +18,8 @@ * 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.quartz +package com.vitorpamplona.quartz.utils expect fun platform(): String + +expect fun currentTimeSeconds(): Long diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/RandomInstance.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/RandomInstance.kt similarity index 90% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/RandomInstance.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/RandomInstance.kt index 5063f34277..557c0b3831 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/RandomInstance.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/RandomInstance.kt @@ -20,10 +20,8 @@ */ package com.vitorpamplona.quartz.utils -import java.security.SecureRandom - object RandomInstance { - private val randomizer = SecureRandom() + val randomizer = SecureRandom() fun int(bound: Int = Int.MAX_VALUE) = randomizer.nextInt(bound) @@ -33,5 +31,5 @@ object RandomInstance { fun randomChar() = charPool[randomizer.nextInt(charPool.size)] - fun randomChars(size: Int = 16) = String(CharArray(size) { randomChar() }) + fun randomChars(size: Int = 16) = CharArray(size) { randomChar() }.concatToString() } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Rfc3986.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Rfc3986.kt new file mode 100644 index 0000000000..6ef3b21193 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Rfc3986.kt @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +expect object Rfc3986 { + fun normalize(uri: String): String + + fun isValidUrl(url: String): Boolean + + fun normalizeAndRemoveFragment(url: String): String + + fun host(url: String): String +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.kt new file mode 100644 index 0000000000..678b26f249 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.kt @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +expect object Secp256k1Instance { + fun compressedPubKeyFor(privKey: ByteArray): ByteArray + + fun isPrivateKeyValid(il: ByteArray): Boolean + + fun signSchnorr( + data: ByteArray, + privKey: ByteArray, + nonce: ByteArray? = RandomInstance.bytes(32), + ): ByteArray + + fun signSchnorr( + data: ByteArray, + privKey: ByteArray, + ): ByteArray + + fun verifySchnorr( + signature: ByteArray, + hash: ByteArray, + pubKey: ByteArray, + ): Boolean + + fun privateKeyAdd( + first: ByteArray, + second: ByteArray, + ): ByteArray + + fun pubKeyTweakMulCompact( + pubKey: ByteArray, + privateKey: ByteArray, + ): ByteArray +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.kt new file mode 100644 index 0000000000..e9b7097cf0 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.kt @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +expect class SecureRandom() { + fun nextInt(bound: Int): Int + + fun nextBytes(output: ByteArray) +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/Platform.ios.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/StringExt.kt similarity index 93% rename from quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/Platform.ios.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/StringExt.kt index 60e069e46a..8074933d3b 100644 --- a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/Platform.ios.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/StringExt.kt @@ -18,6 +18,6 @@ * 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.quartz +package com.vitorpamplona.quartz.utils -actual fun platform() = "iOS" +expect fun String.internIfPossible(): String diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/StringUtils.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/StringUtils.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/StringUtils.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/StringUtils.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/TimeUtils.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/TimeUtils.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/TimeUtils.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/TimeUtils.kt index 0bd1ceec20..565a608620 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/TimeUtils.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/TimeUtils.kt @@ -33,7 +33,7 @@ object TimeUtils { const val ONE_MONTH = 30 * ONE_DAY const val ONE_YEAR = 365 * ONE_DAY - fun now() = System.currentTimeMillis() / 1000 + fun now() = currentTimeSeconds() fun tenSecondsFromNow() = now() + TEN_SECONDS diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/UnicodeNormalizer.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/UnicodeNormalizer.kt new file mode 100644 index 0000000000..95868b19f0 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/UnicodeNormalizer.kt @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +/** + * This class provides the method normalize which transforms + * Unicode text into an equivalent composed or decomposed form, + * allowing for easier sorting and searching of text. The normalize + * method supports the standard normalization forms described in + * Unicode Standard Annex #15 — Unicode Normalization Forms . + */ +expect class UnicodeNormalizer() { + fun normalizeNFKC(input: String): String +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.kt new file mode 100644 index 0000000000..48b10c1295 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.kt @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +expect class UriParser( + uri: String, +) { + fun scheme(): String? + + fun host(): String? + + fun port(): Int? + + fun path(): String? + + fun queryParameterNames(): Set + + fun getQueryParameter(param: String): String? + + fun fragments(): Map +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/UrlEncoder.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/UrlEncoder.kt new file mode 100644 index 0000000000..cc1294b27e --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/UrlEncoder.kt @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +expect object UrlEncoder { + fun encode(value: String): String + + fun decode(value: String): String +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Urls.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Urls.kt new file mode 100644 index 0000000000..57f97a5006 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/Urls.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +expect fun fastFindURLs(text: String): List diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/CacheCollectors.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/CacheCollectors.kt new file mode 100644 index 0000000000..8400c50d22 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/CacheCollectors.kt @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2025 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.quartz.utils.cache + +object CacheCollectors { + fun interface BiFilter { + fun filter( + k: K, + v: V, + ): Boolean + } + + fun interface BiMapper { + fun map( + k: K, + v: V, + ): R? + } + + fun interface BiMapperNotNull { + fun map( + k: K, + v: V, + ): R + } + + fun interface BiNotNullMapper { + fun map( + k: K, + v: V, + ): R + } + + fun interface BiSumOf { + fun map( + k: K, + v: V, + ): Int + } + + fun interface BiSumOfLong { + fun map( + k: K, + v: V, + ): Long + } +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/ICacheOperations.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/ICacheOperations.kt new file mode 100644 index 0000000000..ec4a93d4b0 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/ICacheOperations.kt @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2025 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.quartz.utils.cache + +fun interface ICacheBiConsumer { + fun accept( + k: K, + v: V, + ) +} + +interface ICacheOperations { + fun size(): Int + + fun forEach(consumer: ICacheBiConsumer): Unit + + fun filter(consumer: CacheCollectors.BiFilter): List + + fun filterIntoSet(consumer: CacheCollectors.BiFilter): Set + + fun map(consumer: CacheCollectors.BiNotNullMapper): List + + fun mapNotNull(consumer: CacheCollectors.BiMapper): List + + fun mapNotNullIntoSet(consumer: CacheCollectors.BiMapper): Set + + fun mapFlatten(consumer: CacheCollectors.BiMapper?>): List + + fun mapFlattenIntoSet(consumer: CacheCollectors.BiMapper?>): Set + + fun maxOrNullOf( + filter: CacheCollectors.BiFilter, + comparator: Comparator, + ): V? + + fun sumOf(consumer: CacheCollectors.BiSumOf): Int + + fun sumOfLong(consumer: CacheCollectors.BiSumOfLong): Long + + fun groupBy(consumer: CacheCollectors.BiNotNullMapper): Map> + + fun countByGroup(consumer: CacheCollectors.BiNotNullMapper): Map + + fun sumByGroup( + groupMap: CacheCollectors.BiNotNullMapper, + sumOf: CacheCollectors.BiNotNullMapper, + ): Map + + fun count(consumer: CacheCollectors.BiFilter): Int + + fun associate(transform: (K, V) -> Pair): Map + + fun associateWith(transform: (K, V) -> U?): Map + + fun joinToString( + separator: CharSequence = ", ", + prefix: CharSequence = "", + postfix: CharSequence = "", + limit: Int = -1, + truncated: CharSequence = "...", + transform: ((K, V) -> CharSequence)? = null, + ): String +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.kt new file mode 100644 index 0000000000..96a18f5204 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.kt @@ -0,0 +1,103 @@ +/** + * Copyright (c) 2025 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.quartz.utils.cache + +expect class LargeCache() : ICacheOperations { + fun keys(): Set + + fun values(): Iterable + + fun get(key: K): V? + + fun remove(key: K): V? + + override fun size(): Int + + fun isEmpty(): Boolean + + fun clear() + + fun containsKey(key: K): Boolean + + fun put( + key: K, + value: V, + ) + + fun getOrCreate( + key: K, + builder: (key: K) -> V, + ): V + + fun createIfAbsent( + key: K, + builder: (key: K) -> V, + ): Boolean + + override fun forEach(consumer: ICacheBiConsumer): Unit + + override fun filter(consumer: CacheCollectors.BiFilter): List + + override fun filterIntoSet(consumer: CacheCollectors.BiFilter): Set + + override fun map(consumer: CacheCollectors.BiNotNullMapper): List + + override fun mapNotNull(consumer: CacheCollectors.BiMapper): List + + override fun mapNotNullIntoSet(consumer: CacheCollectors.BiMapper): Set + + override fun mapFlatten(consumer: CacheCollectors.BiMapper?>): List + + override fun mapFlattenIntoSet(consumer: CacheCollectors.BiMapper?>): Set + + override fun maxOrNullOf( + filter: CacheCollectors.BiFilter, + comparator: Comparator, + ): V? + + override fun sumOf(consumer: CacheCollectors.BiSumOf): Int + + override fun sumOfLong(consumer: CacheCollectors.BiSumOfLong): Long + + override fun groupBy(consumer: CacheCollectors.BiNotNullMapper): Map> + + override fun countByGroup(consumer: CacheCollectors.BiNotNullMapper): Map + + override fun sumByGroup( + groupMap: CacheCollectors.BiNotNullMapper, + sumOf: CacheCollectors.BiNotNullMapper, + ): Map + + override fun count(consumer: CacheCollectors.BiFilter): Int + + override fun associate(transform: (K, V) -> Pair): Map + + override fun associateWith(transform: (K, V) -> U?): Map + + override fun joinToString( + separator: CharSequence, + prefix: CharSequence, + postfix: CharSequence, + limit: Int, + truncated: CharSequence, + transform: ((K, V) -> CharSequence)?, + ): String +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESCBC.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESCBC.kt new file mode 100644 index 0000000000..f30fc70b3d --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESCBC.kt @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2025 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.quartz.utils.ciphers + +import com.vitorpamplona.quartz.utils.RandomInstance + +expect class AESCBC( + keyBytes: ByteArray = RandomInstance.bytes(32), + iv: ByteArray = RandomInstance.bytes(16), +) : NostrCipher { + val keyBytes: ByteArray + val iv: ByteArray + + override fun name(): String + + override fun encrypt(bytesToEncrypt: ByteArray): ByteArray + + override fun decrypt(bytesToDecrypt: ByteArray): ByteArray + + override fun decryptOrNull(bytesToDecrypt: ByteArray): ByteArray? +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.kt new file mode 100644 index 0000000000..3a5dfa2e5c --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.kt @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2025 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.quartz.utils.ciphers + +import com.vitorpamplona.quartz.utils.RandomInstance + +expect class AESGCM( + keyBytes: ByteArray = RandomInstance.bytes(32), + nonce: ByteArray = RandomInstance.bytes(16), +) : NostrCipher { + val keyBytes: ByteArray + val nonce: ByteArray + + override fun name(): String + + override fun encrypt(bytesToEncrypt: ByteArray): ByteArray + + override fun decrypt(bytesToDecrypt: ByteArray): ByteArray + + override fun decryptOrNull(bytesToDecrypt: ByteArray): ByteArray? +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/encryption/NostrCipher.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/NostrCipher.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/encryption/NostrCipher.kt rename to quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/NostrCipher.kt index 0f94fa8ac3..e6b986b9e1 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/encryption/NostrCipher.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/NostrCipher.kt @@ -18,7 +18,7 @@ * 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.quartz.nip17Dm.files.encryption +package com.vitorpamplona.quartz.utils.ciphers interface NostrCipher { fun name(): String diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/diggest/DigestInstance.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/diggest/DigestInstance.kt new file mode 100644 index 0000000000..a60a9d9ef1 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/diggest/DigestInstance.kt @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2025 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.quartz.utils.diggest + +expect class DigestInstance( + algorithm: String, +) { + fun update(array: ByteArray) + + fun update(byte: Byte) + + fun digest(): ByteArray + + fun digest(input: ByteArray): ByteArray +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/mac/MacInstance.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/mac/MacInstance.kt new file mode 100644 index 0000000000..efc1ce09dc --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/mac/MacInstance.kt @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2025 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.quartz.utils.mac + +expect class MacInstance( + algorithm: String, + key: ByteArray, +) { + fun init( + key: ByteArray, + algorithm: String, + ) + + fun getMacLength(): Int + + fun update(array: ByteArray) + + fun update(byte: Byte) + + fun doFinal(): ByteArray + + fun doFinal( + output: ByteArray, + offset: Int = 0, + ) +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.kt new file mode 100644 index 0000000000..74cef2daff --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2025 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.quartz.utils.sha256 + +expect fun sha256(data: ByteArray): ByteArray diff --git a/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/RandomInstanceTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/RandomInstanceTest.kt new file mode 100644 index 0000000000..9219875417 --- /dev/null +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/RandomInstanceTest.kt @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2025 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.quartz + +import com.vitorpamplona.quartz.utils.RandomInstance +import kotlin.collections.all +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class RandomInstanceTest { + @Test + fun testRandomByteArray() { + val random = RandomInstance.bytes(32) + assertEquals(32, random.size) + assertTrue(!random.all { it == 0.toByte() }) + } + + @Test + fun testRandomInt() { + val random = RandomInstance.int(23) + assertTrue(random < 23, random.toString()) + assertTrue(random >= 0, random.toString()) + } + + @Test + fun testRandomChars() { + val random = RandomInstance.randomChars(32) + assertEquals(32, random.length) + assertTrue(random.isNotBlank()) + } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/CalendarPureJavaBuilder.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/TestResourceLoader.kt similarity index 80% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/CalendarPureJavaBuilder.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/TestResourceLoader.kt index a98bcd23d6..e44ed5e8fa 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/http/CalendarPureJavaBuilder.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/TestResourceLoader.kt @@ -18,11 +18,7 @@ * 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.quartz.nip03Timestamp.ots.http - -import com.vitorpamplona.quartz.nip03Timestamp.ots.CalendarBuilder -import com.vitorpamplona.quartz.nip03Timestamp.ots.ICalendar -import com.vitorpamplona.quartz.nip03Timestamp.ots.ICalendarAsyncSubmit +package com.vitorpamplona.quartz /** * Copyright (c) 2025 Vitor Pamplona @@ -44,11 +40,6 @@ import com.vitorpamplona.quartz.nip03Timestamp.ots.ICalendarAsyncSubmit * 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. */ -class CalendarPureJavaBuilder : CalendarBuilder { - override fun newSyncCalendar(url: String): ICalendar = Calendar(url) - - override fun newAsyncCalendar( - url: String, - digest: ByteArray, - ): ICalendarAsyncSubmit = CalendarAsyncSubmit(url, digest) +expect class TestResourceLoader() { + fun loadString(file: String): String } diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/lightning/Lud06Test.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/lightning/Lud06Test.kt similarity index 96% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/lightning/Lud06Test.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/lightning/Lud06Test.kt index 2afb0bb415..536be79735 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/lightning/Lud06Test.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/lightning/Lud06Test.kt @@ -20,8 +20,8 @@ */ package com.vitorpamplona.quartz.lightning -import org.junit.Assert.assertEquals -import org.junit.Test +import kotlin.test.Test +import kotlin.test.assertEquals class Lud06Test { val lnTips = diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/BloomFilterMurMur3Test.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/BloomFilterMurMur3Test.kt similarity index 85% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/BloomFilterMurMur3Test.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/BloomFilterMurMur3Test.kt index 20887c96ba..a20cd47779 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/BloomFilterMurMur3Test.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/BloomFilterMurMur3Test.kt @@ -23,10 +23,11 @@ package com.vitorpamplona.quartz.nip01Core.hints import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.hints.bloom.BloomFilterMurMur3 import com.vitorpamplona.quartz.utils.RandomInstance -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertFalse -import junit.framework.TestCase.assertTrue -import org.junit.Test +import kotlin.test.DefaultAsserter.assertTrue +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue class BloomFilterMurMur3Test { val testEncoded = "100:10:AKiEIEQKALgRACEABA==:3" @@ -38,7 +39,7 @@ class BloomFilterMurMur3Test { val keys = mutableListOf().apply { - for (seed in 0..1_000_000) { + repeat(1_000_000) { add(RandomInstance.bytes(32)) } } @@ -85,30 +86,28 @@ class BloomFilterMurMur3Test { } @Test - fun runProb2() { + fun runProb10MbitFilterShouldStore1MKeysWith1PercentFalsePositive() { val bloomFilter = BloomFilterMurMur3(10_000_000, 4) keys.forEach(bloomFilter::add) var failureCounter = 0 + + keys.forEach { key -> + if (!bloomFilter.mightContain(key)) { + failureCounter++ + } + } + + // Bloom filters always know if a key is in. + assertEquals(0, failureCounter) + + failureCounter = 0 repeat(1_000_000) { if (bloomFilter.mightContain(RandomInstance.bytes(32))) { failureCounter++ } } - assertTrue("Failures $failureCounter ${failureCounter / 1_000_000.0}", failureCounter / 1_000_000.0f < 0.015) - } - @Test - fun runProb3() { - val bloomFilter = BloomFilterMurMur3(10_000_000, 4) - keys.forEach(bloomFilter::add) - - var failureCounter = 0 - repeat(1_000_000) { - if (bloomFilter.mightContain(RandomInstance.bytes(32))) { - failureCounter++ - } - } assertTrue("Failures $failureCounter ${failureCounter / 1_000_000.0}", failureCounter / 1_000_000.0f < 0.015) } } diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexerTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexerTest.kt similarity index 57% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexerTest.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexerTest.kt index f58a4cf7da..e362ede014 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexerTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/HintIndexerTest.kt @@ -20,79 +20,83 @@ */ package com.vitorpamplona.quartz.nip01Core.hints +import com.vitorpamplona.quartz.TestResourceLoader +import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.toHexKey +import com.vitorpamplona.quartz.nip01Core.hints.HintIndexerTest.Companion.addresses +import com.vitorpamplona.quartz.nip01Core.hints.HintIndexerTest.Companion.eventIds +import com.vitorpamplona.quartz.nip01Core.hints.HintIndexerTest.Companion.indexer +import com.vitorpamplona.quartz.nip01Core.hints.HintIndexerTest.Companion.keys import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address +import com.vitorpamplona.quartz.nip01Core.relay.normalizer.isLocalHost import com.vitorpamplona.quartz.utils.RandomInstance -import com.vitorpamplona.quartz.utils.usedMemoryMb -import junit.framework.TestCase.assertTrue -import org.junit.Test +import kotlin.test.DefaultAsserter.assertTrue +import kotlin.test.Test class HintIndexerTest { companion object { - val VALID_CHARS: List = ('0'..'9') + ('a'..'z') + ('A'..'Z') - - private fun randomChars(size: Int): String = CharArray(size) { VALID_CHARS.random() }.concatToString() - val keys = - mutableListOf().apply { - for (seed in 0..1_000_000) { - add(RandomInstance.bytes(32).toHexKey()) - } - } + mutableListOf() + .apply { + repeat(200_000) { + add(RandomInstance.bytes(32).toHexKey()) + } + }.toSet() val eventIds = mutableListOf().apply { - for (seed in 0..1_000_000) { + repeat(200_000) { add(RandomInstance.bytes(32).toHexKey()) } } val addresses = - keys.take(100_000).map { + keys.take(30_000).map { Address.assemble( RandomInstance.int(65_000), it, - randomChars(10), + RandomInstance.randomChars(10), ) } val relays = - this::class.java - .getResourceAsStream("relayDB.txt") - ?.readAllBytes() - .toString() - .split("\n") - .mapNotNull { RelayUrlNormalizer.normalizeOrNull(it) } + TestResourceLoader() + .loadString("relayDB.txt") + .split('\n') + .mapNotNull { + val relay = RelayUrlNormalizer.normalizeOrNull(it) + if (relay == null || relay.isLocalHost()) { + null + } else { + relay + } + } val indexer by lazy { - System.gc() - Thread.sleep(1000) - - val startingMemory = Runtime.getRuntime().usedMemoryMb() val result = HintIndexer() - val endingMemory = Runtime.getRuntime().usedMemoryMb() - println("Filter using ${endingMemory - startingMemory}MB") + println("${keys.size} ${relays.size}") // Simulates 5 outbox relays for each key keys.forEach { key -> - (0..5).map { + repeat(5) { result.addKey(key, relays.random()) } } - // Simulates each event being in 8 + 0..10 relays. + println("${keys.size}") + + // Simulates each event being in 5 + 0..10 relays. eventIds.forEach { id -> - repeat(8 + RandomInstance.int(10)) { + repeat(5 + RandomInstance.int(10)) { result.addEvent(id, relays.random()) } } - // Simulates each address being in 8 + 0..10 relays. + // Simulates each address being in 5 + 0..10 relays. addresses.forEach { address -> - repeat(8 + RandomInstance.int(10)) { + repeat(5 + RandomInstance.int(10)) { result.addAddress(address, relays.random()) } } @@ -104,7 +108,7 @@ class HintIndexerTest { val testSize = 1000 val testProb = 0.02f - fun assert99PercentSucess(success: () -> Boolean) { + fun assert99PercentSuccess(success: () -> Boolean) { var failureCounter = 0 repeat(testSize) { if (!success()) { @@ -118,46 +122,61 @@ class HintIndexerTest { ) } + fun assert100PercentSuccess(success: () -> Boolean) { + var failureCounter = 0 + repeat(testSize) { + if (!success()) { + failureCounter++ + } + } + + assertTrue( + "Failure rate: $failureCounter of 1000 elements => ${(failureCounter / testSize.toFloat()) * 100}%", + failureCounter == 0, + ) + } + @Test fun runProbExistingKeys() = - assert99PercentSucess { + assert100PercentSuccess { indexer.hintsForKey(keys.random()).isNotEmpty() } @Test fun runProbNewKeys() = - assert99PercentSucess { - indexer.hintsForKey(RandomInstance.bytes(32)).isEmpty() + assert99PercentSuccess { + // 99% of the queries return less than 2 relays. + indexer.hintsForKey(RandomInstance.bytes(32)).size < 3 } @Test fun runProbExistingEventIds() = - assert99PercentSucess { + assert100PercentSuccess { indexer.hintsForEvent(eventIds.random()).isNotEmpty() } @Test fun runProbNewEventIds() = - assert99PercentSucess { - indexer.hintsForEvent(RandomInstance.bytes(32)).isEmpty() + assert99PercentSuccess { + indexer.hintsForEvent(RandomInstance.bytes(32)).size < 3 } @Test fun runProbExistingAddresses() = - assert99PercentSucess { + assert100PercentSuccess { indexer.hintsForAddress(addresses.random()).isNotEmpty() } @Test fun runProbNewAddresses() = - assert99PercentSucess { + assert99PercentSuccess { val newAddress = Address.assemble( RandomInstance.int(65000), RandomInstance.bytes(32).toHexKey(), - randomChars(10), + RandomInstance.randomChars(10), ) - indexer.hintsForAddress(newAddress).isEmpty() + indexer.hintsForAddress(newAddress).size < 3 } } diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/MurMur3Test.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/MurMur3Test.kt similarity index 98% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/MurMur3Test.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/MurMur3Test.kt index dc9ac38ea5..e71edcbbe7 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/MurMur3Test.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/hints/MurMur3Test.kt @@ -23,8 +23,8 @@ package com.vitorpamplona.quartz.nip01Core.hints import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray import com.vitorpamplona.quartz.nip01Core.hints.bloom.MurmurHash3 -import junit.framework.TestCase.assertEquals -import org.junit.Test +import kotlin.test.Test +import kotlin.test.assertEquals class MurMur3Test { class Case( diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializerTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializerTest.kt similarity index 81% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializerTest.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializerTest.kt index cb22c26ba9..8867221052 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializerTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializerTest.kt @@ -21,10 +21,12 @@ package com.vitorpamplona.quartz.nip01Core.jackson import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair +import com.vitorpamplona.quartz.nip01Core.crypto.verify import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal -import com.vitorpamplona.quartz.nip01Core.verify -import org.junit.Test +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue class EventDeserializerTest { @Test @@ -34,7 +36,7 @@ class EventDeserializerTest { val json = template.toJson() - assert(json == templateJson) + assertEquals(json, templateJson) } @Test @@ -42,9 +44,9 @@ class EventDeserializerTest { val templateJson = """{"kind":"1","content":"This is an unsigned event.","created_at":1234,"tags":[]}""" val template = EventTemplate.fromJson(templateJson) - assert(template.kind == 1) - assert(template.content == "This is an unsigned event.") - assert(template.tags.isEmpty()) + assertEquals(1, template.kind) + assertEquals("This is an unsigned event.", template.content) + assertTrue(template.tags.isEmpty()) } @Test @@ -57,9 +59,9 @@ class EventDeserializerTest { val signedEvent = signer.signerSync.sign(template)!! - assert(signedEvent.id.isNotEmpty()) - assert(signedEvent.sig.isNotEmpty()) - assert(signedEvent.pubKey.isNotEmpty()) - assert(signedEvent.verify()) + assertTrue(signedEvent.id.isNotEmpty()) + assertTrue(signedEvent.sig.isNotEmpty()) + assertTrue(signedEvent.pubKey.isNotEmpty()) + assertTrue(signedEvent.verify()) } } diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/InliningTagArrayPrettyPrinterTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/InliningTagArrayPrettyPrinterTest.kt similarity index 99% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/InliningTagArrayPrettyPrinterTest.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/InliningTagArrayPrettyPrinterTest.kt index 39f7bef06c..39d8c4be94 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/InliningTagArrayPrettyPrinterTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/InliningTagArrayPrettyPrinterTest.kt @@ -22,7 +22,7 @@ package com.vitorpamplona.quartz.nip01Core.jackson import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import org.junit.Assert.assertEquals -import org.junit.Test +import kotlin.test.Test class InliningTagArrayPrettyPrinterTest { val mapper = diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/UpdateMetadataTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/UpdateMetadataTest.kt similarity index 97% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/UpdateMetadataTest.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/UpdateMetadataTest.kt index 674d72bb02..4c0b38be20 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/UpdateMetadataTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/metadata/UpdateMetadataTest.kt @@ -22,10 +22,11 @@ package com.vitorpamplona.quartz.nip01Core.metadata import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.jackson.EventManualSerializer -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper import com.vitorpamplona.quartz.utils.nsecToSigner import org.junit.Assert.assertEquals -import org.junit.Test +import kotlin.test.Test +import kotlin.test.assertEquals class UpdateMetadataTest { val signer = "nsec10g0wheggqn9dawlc0yuv6adnat6n09anr7eyykevw2dm8xa5fffs0wsdsr".nsecToSigner() @@ -35,7 +36,7 @@ class UpdateMetadataTest { */ fun Event.toPrettyJson(): String { val obj = EventManualSerializer.assemble(id, pubKey, createdAt, kind, tags, content, sig) - return JsonMapper.mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj) + return JacksonMapper.mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj) } @Test diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/relay/RelayUrlFormatterTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/relay/RelayUrlFormatterTest.kt similarity index 97% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/relay/RelayUrlFormatterTest.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/relay/RelayUrlFormatterTest.kt index fd936867ac..7046609cb1 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip01Core/relay/RelayUrlFormatterTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/relay/RelayUrlFormatterTest.kt @@ -21,8 +21,8 @@ package com.vitorpamplona.quartz.nip01Core.relay import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import junit.framework.TestCase.assertEquals -import org.junit.Test +import kotlin.test.Test +import kotlin.test.assertEquals class RelayUrlFormatterTest { @Test diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/Nip05Test.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/Nip05Test.kt similarity index 96% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/Nip05Test.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/Nip05Test.kt index 675789e6fa..d5b55b61a0 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/Nip05Test.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/Nip05Test.kt @@ -21,10 +21,10 @@ package com.vitorpamplona.quartz.nip05DnsIdentifiers import kotlinx.coroutines.runBlocking -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNull -import org.junit.Assert.fail -import org.junit.Test +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNull +import kotlin.test.fail class Nip05Test { companion object { diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/NIP19ParserTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/NIP19ParserTest.kt similarity index 91% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/NIP19ParserTest.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/NIP19ParserTest.kt index c4609ba934..4fc3a33fb5 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/NIP19ParserTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/NIP19ParserTest.kt @@ -22,32 +22,31 @@ package com.vitorpamplona.quartz.nip19Bech32 import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag import com.vitorpamplona.quartz.nip19Bech32.bech32.bechToBytes import com.vitorpamplona.quartz.nip19Bech32.entities.NAddress import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent import com.vitorpamplona.quartz.nip19Bech32.entities.NNote import com.vitorpamplona.quartz.nip19Bech32.entities.NProfile import com.vitorpamplona.quartz.nip19Bech32.entities.NPub -import org.junit.Assert -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNotNull -import org.junit.Assert.assertTrue -import org.junit.Test +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertTrue class NIP19ParserTest { @Test() fun uri_to_route_null() { val actual = Nip19Parser.uriToRoute(null) - Assert.assertEquals(null, actual) + assertEquals(null, actual) } @Test() fun uri_to_route_unknown() { val actual = Nip19Parser.uriToRoute("nostr:unknown") - Assert.assertEquals(null, actual) + assertEquals(null, actual) } @Test() @@ -55,10 +54,10 @@ class NIP19ParserTest { val actual = Nip19Parser.uriToRoute("nostr:npub1hv7k2s755n697sptva8vkh9jz40lzfzklnwj6ekewfmxp5crwdjs27007y") - Assert.assertTrue(actual?.entity is NPub) - Assert.assertEquals( + assertTrue(actual?.entity is NPub) + assertEquals( "bb3d6543d4a4f45f402b674ecb5cb2155ff12456fcdd2d66d9727660d3037365", - (actual?.entity as? NPub)?.hex, + actual.entity.hex, ) } @@ -68,9 +67,9 @@ class NIP19ParserTest { Nip19Parser.uriToRoute("nostr:note1stqea6wmwezg9x6yyr6qkukw95ewtdukyaztycws65l8wppjmtpscawevv")?.entity as? NNote assertNotNull(result) - Assert.assertEquals( + assertEquals( "82c19ee9db7644829b4420f40b72ce2d32e5b7962744b261d0d53e770432dac3", - result?.hex, + result.hex, ) } @@ -78,62 +77,62 @@ class NIP19ParserTest { fun uri_to_route_nprofile() { val actual = Nip19Parser.uriToRoute("nostr:nprofile") - Assert.assertEquals(null, actual) + assertEquals(null, actual) } @Test() fun uri_to_route_incomplete_nevent() { val actual = Nip19Parser.uriToRoute("nostr:nevent") - Assert.assertEquals(null, actual) + assertEquals(null, actual) } @Test() fun uri_to_route_incomplete_nrelay() { val actual = Nip19Parser.uriToRoute("nostr:nrelay") - Assert.assertEquals(null, actual) + assertEquals(null, actual) } @Test() fun uri_to_route_incomplete_naddr() { val actual = Nip19Parser.uriToRoute("nostr:naddr") - Assert.assertEquals(null, actual) + assertEquals(null, actual) } @Test() fun uri_to_route_complete_nprofile_2() { val actual = Nip19Parser.uriToRoute("nostr:nprofile1qqsyvrp9u6p0mfur9dfdru3d853tx9mdjuhkphxuxgfwmryja7zsvhqpzamhxue69uhhv6t5daezumn0wd68yvfwvdhk6tcpz9mhxue69uhkummnw3ezuamfdejj7qgwwaehxw309ahx7uewd3hkctcscpyug") - Assert.assertNotNull(actual) - Assert.assertTrue(actual?.entity is NProfile) - Assert.assertEquals("460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c", (actual?.entity as? NProfile)?.hex) - Assert.assertEquals(NormalizedRelayUrl("wss://vitor.nostr1.com/"), (actual?.entity as? NProfile)?.relay?.first()) + assertNotNull(actual) + assertTrue(actual?.entity is NProfile) + assertEquals("460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c", (actual?.entity as? NProfile)?.hex) + assertEquals(NormalizedRelayUrl("wss://vitor.nostr1.com/"), (actual?.entity as? NProfile)?.relay?.first()) } @Test() fun uri_to_route_complete_nprofile() { val actual = Nip19Parser.uriToRoute("nostr:nprofile1qy2hwumn8ghj7un9d3shjtnyv9kh2uewd9hj7qgwwaehxw309ahx7uewd3hkctcpr9mhxue69uhhyetvv9ujuumwdae8gtnnda3kjctv9uqzq9thu3vem5gvsc6f3l3uyz7c92h6lq56t9wws0zulzkrgc6nrvym5jfztf") - Assert.assertTrue(actual?.entity is NProfile) - Assert.assertEquals("1577e4599dd10c863498fe3c20bd82aafaf829a595ce83c5cf8ac3463531b09b", (actual?.entity as? NProfile)?.hex) + assertTrue(actual?.entity is NProfile) + assertEquals("1577e4599dd10c863498fe3c20bd82aafaf829a595ce83c5cf8ac3463531b09b", (actual?.entity as? NProfile)?.hex) } @Test() fun uri_to_route_complete_nevent() { val actual = Nip19Parser.uriToRoute("nostr:nevent1qy2hwumn8ghj7un9d3shjtnyv9kh2uewd9hj7qgwwaehxw309ahx7uewd3hkctcpr9mhxue69uhhyetvv9ujuumwdae8gtnnda3kjctv9uq36amnwvaz7tmjv4kxz7fwvd5xjcmpvahhqmr9vfejucm0d5hsz9mhwden5te0wfjkccte9ec8y6tdv9kzumn9wshsz8thwden5te0dehhxarj9ekh2arfdeuhwctvd3jhgtnrdakj7qg3waehxw309ucngvpwvcmh5tnfduhszythwden5te0dehhxarj9emkjmn99uq3jamnwvaz7tmhv4kxxmmdv5hxummnw3ezuamfdejj7qpqvsup5xk3e2quedxjvn2gjppc0lqny5dmnr2ypc9tftwmdxta0yjqrd6n50") - Assert.assertTrue(actual?.entity is NEvent) - Assert.assertEquals("64381a1ad1ca81ccb4d264d48904387fc13251bb98d440e0ab4addb6997d7924", (actual?.entity as? NEvent)?.hex) + assertTrue(actual?.entity is NEvent) + assertEquals("64381a1ad1ca81ccb4d264d48904387fc13251bb98d440e0ab4addb6997d7924", (actual?.entity as? NEvent)?.hex) } @Test() fun uri_to_route_complete_naddr() { val actual = Nip19Parser.uriToRoute("nostr:naddr1qqyxzmt9w358jum5qyt8wumn8ghj7un9d3shjtnwdaehgu3wvfskueqzypd7v3r24z33cydnk3fmlrd0exe5dlej3506zxs05q4puerp765mzqcyqqq8scsq6mk7u") - Assert.assertTrue(actual?.entity is NAddress) - Assert.assertEquals("30818:5be6446aa8a31c11b3b453bf8dafc9b346ff328d1fa11a0fa02a1e6461f6a9b1:amethyst", (actual?.entity as? NAddress)?.aTag()) + assertTrue(actual?.entity is NAddress) + assertEquals("30818:5be6446aa8a31c11b3b453bf8dafc9b346ff328d1fa11a0fa02a1e6461f6a9b1:amethyst", (actual?.entity as? NAddress)?.aTag()) } @Test @@ -357,7 +356,7 @@ class NIP19ParserTest { assertNotNull(result) assertEquals("1f878e82063d80f41a781d3a2ef7bc336f1beb7942bf3b49b42aee1251eb5cf0", result?.hex) - assertEquals(NormalizedRelayUrl("wss://relay.damus.io/"), result?.relay?.get(0)) + assertEquals(NormalizedRelayUrl("wss://relay.damus.io/"), result.relay.get(0)) assertEquals("460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c", result?.author) assertEquals(1, result?.kind) } diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvIntegerTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvIntegerTest.kt similarity index 99% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvIntegerTest.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvIntegerTest.kt index 7255da0248..3cfca47c8e 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvIntegerTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip19Bech32/TlvIntegerTest.kt @@ -24,7 +24,7 @@ import com.vitorpamplona.quartz.nip19Bech32.tlv.to32BitByteArray import com.vitorpamplona.quartz.nip19Bech32.tlv.toInt32 import org.junit.Assert import org.junit.Assert.assertEquals -import org.junit.Test +import kotlin.test.Test class TlvIntegerTest { fun to_int_32_length_smaller_than_4() { diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/Nip30Test.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/Nip30Test.kt similarity index 97% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/Nip30Test.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/Nip30Test.kt index 6ca46f02d4..6d443a2ea4 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/Nip30Test.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip30CustomEmoji/Nip30Test.kt @@ -20,10 +20,10 @@ */ package com.vitorpamplona.quartz.nip30CustomEmoji -import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertNull -import org.junit.Test +import com.vitorpamplona.quartz.nip01Core.core.ImmutableListOfLists +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNull class Nip30Test { @Test() diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/HkdfText.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/HkdfText.kt similarity index 96% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/HkdfText.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/HkdfText.kt index f6e9cfb11c..212a126c0f 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/HkdfText.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/HkdfText.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.quartz.nip44Encryption.crypto import com.vitorpamplona.quartz.nip01Core.core.toHexKey -import org.junit.Test +import kotlin.test.Test import kotlin.test.assertEquals class HkdfText { @@ -31,6 +31,8 @@ class HkdfText { @Test fun testExpand1() { + /* + Removed in the conversion to KMP val result = hkdf.expand( "b0a6232d3e5444dbf2291f3290504989716f1dc78ac2da812230720fd76c8f06".hexToByteArray(), @@ -41,7 +43,7 @@ class HkdfText { assertEquals("9077071b92dfbd725f5a1dd2dbbf349615f1d0ce22b436e2f505cc05984ef588", result.hmacKey.toHexKey()) assertEquals("3256a46b762158a6e08338daf2c5b3eefd2bed343cb22df8b6315567b9207cef", result.chachaKey.toHexKey()) assertEquals("670bb239ac07dbb801653aa5", result.chachaNonce.toHexKey()) - +*/ val result2 = hkdf.fastExpand( "b0a6232d3e5444dbf2291f3290504989716f1dc78ac2da812230720fd76c8f06".hexToByteArray(), @@ -55,6 +57,8 @@ class HkdfText { @Test fun testExpand2() { + /* + Removed in the conversion to KMP val result = hkdf.expand( "bc5d4e032696ef107ef1c7b6fc5f00c6e7b31ae4f86ee486ce24aa0d84847d83".hexToByteArray(), @@ -65,7 +69,7 @@ class HkdfText { assertEquals("26ccd9471681fc42459dbf7b14fc54d3f5276ddad482f7c9f81dc021ccbe5592", result.hmacKey.toHexKey()) assertEquals("a13a519db107cf9ecbca6ba79ab2428fcd624286025b7ee452f153ae770f07a8", result.chachaKey.toHexKey()) assertEquals("4c8218640c43de928f4c52e1", result.chachaNonce.toHexKey()) - + */ val result2 = hkdf.fastExpand( "bc5d4e032696ef107ef1c7b6fc5f00c6e7b31ae4f86ee486ce24aa0d84847d83".hexToByteArray(), @@ -79,6 +83,8 @@ class HkdfText { @Test fun testExpand3() { + /* + Removed in the conversion to KMP val result = hkdf.expand( "0000000000000000000000000000000000000000000000000000000000000000".hexToByteArray(), @@ -89,7 +95,7 @@ class HkdfText { assertEquals("a30b80c908d01aa28eae9dcdec55ac104f9c889b989ee563919985a84f66360d", result.hmacKey.toHexKey()) assertEquals("3769af12ff4dbf44e516a22d1d0512e8bc42516d59e8bf401ea346a4d60dccf7", result.chachaKey.toHexKey()) assertEquals("77938d29bb13ea73f677ac27", result.chachaNonce.toHexKey()) - + */ val result2 = hkdf.fastExpand( "0000000000000000000000000000000000000000000000000000000000000000".hexToByteArray(), diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestTest.kt similarity index 80% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestTest.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestTest.kt index 9202392cbd..fe6c4f7a96 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerRequestTest.kt @@ -20,16 +20,17 @@ */ package com.vitorpamplona.quartz.nip46RemoteSigner -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper -import org.junit.Test +import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper +import kotlin.test.Test +import kotlin.test.assertTrue class BunkerRequestTest { @Test fun testBunkerRequestDeSerialization() { val requestJson = """{"id":"123","method":"sign_event","params":["{\"created_at\":1234,\"kind\":1,\"tags\":[],\"content\":\"This is an unsigned event.\"}"]}""" - val bunkerRequest = JsonMapper.mapper.readValue(requestJson, BunkerRequest::class.java) + val bunkerRequest = OptimizedJsonMapper.fromJsonTo(requestJson) - assert(bunkerRequest is BunkerRequestSign) - assert((bunkerRequest as BunkerRequestSign).event.kind == 1) + assertTrue(bunkerRequest is BunkerRequestSign) + assertTrue((bunkerRequest as BunkerRequestSign).event.kind == 1) } } diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip51Lists/TagArrayExt.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip51Lists/TagArrayExt.kt similarity index 85% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip51Lists/TagArrayExt.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip51Lists/TagArrayExt.kt index b5c40011e7..1d5f3e99dc 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip51Lists/TagArrayExt.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip51Lists/TagArrayExt.kt @@ -23,9 +23,8 @@ package com.vitorpamplona.quartz.nip51Lists import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId import com.vitorpamplona.quartz.experimental.ephemChat.list.tags.RoomIdTag import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import junit.framework.TestCase.assertTrue -import org.junit.Test -import java.util.Arrays +import kotlin.test.Test +import kotlin.test.assertTrue class TagArrayExt { val tags = @@ -42,7 +41,7 @@ class TagArrayExt { @Test fun testRemove() { assertTrue( - Arrays.deepEquals(expectedTags, tags.remove(arrayOf("group", "_", "wss://nos.lol"))), + expectedTags.contentDeepEquals(tags.remove(arrayOf("group", "_", "wss://nos.lol"))), ) } @@ -50,10 +49,7 @@ class TagArrayExt { fun testRemoveParsing() { val removing = RoomId("_", RelayUrlNormalizer.normalize("wss://nos.lol")) assertTrue( - Arrays.deepEquals( - expectedTags, - tags.removeParsing(RoomIdTag::parse, removing), - ), + expectedTags.contentDeepEquals(tags.removeParsing(RoomIdTag::parse, removing)), ) } } diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip65RelayList/RelayListRecommendationProcessorTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip65RelayList/RelayListRecommendationProcessorTest.kt similarity index 97% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip65RelayList/RelayListRecommendationProcessorTest.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip65RelayList/RelayListRecommendationProcessorTest.kt index b90ade3333..1b057da442 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip65RelayList/RelayListRecommendationProcessorTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip65RelayList/RelayListRecommendationProcessorTest.kt @@ -21,9 +21,9 @@ package com.vitorpamplona.quartz.nip65RelayList import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import junit.framework.TestCase.assertEquals -import junit.framework.TestCase.assertTrue -import org.junit.Test +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue class RelayListRecommendationProcessorTest { fun norm(str: String) = RelayUrlNormalizer.normalizeOrNull(str)!! diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip96FileStorage/Nip96Test.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip96FileStorage/Nip96Test.kt similarity index 98% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip96FileStorage/Nip96Test.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip96FileStorage/Nip96Test.kt index 0266f5ba4c..19b7479371 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/nip96FileStorage/Nip96Test.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip96FileStorage/Nip96Test.kt @@ -21,8 +21,8 @@ package com.vitorpamplona.quartz.nip96FileStorage import com.vitorpamplona.quartz.nip96FileStorage.info.ServerInfoParser -import junit.framework.TestCase.assertEquals -import org.junit.Test +import kotlin.test.Test +import kotlin.test.assertEquals class Nip96Test { val relativeUrlTest = @@ -151,7 +151,7 @@ class Nip96Test { assertEquals(true, info.plans["free"]?.isNip98Required) assertEquals("https://nostr.build", info.plans["free"]?.url) assertEquals(26214400L, info.plans["free"]?.maxByteSize) - assertEquals(listOf(0, 0), info.plans["free"]?.fileExpiration) + assertEquals(listOf(0, 0), info.plans["free"]?.fileExpiration?.toList()) assertEquals( listOf("image", "video"), info.plans["free"] diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/utils/HexEncodingTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/utils/HexEncodingTest.kt similarity index 76% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/utils/HexEncodingTest.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/utils/HexEncodingTest.kt index 2ca733f3a3..bf577249ce 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/utils/HexEncodingTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/utils/HexEncodingTest.kt @@ -20,11 +20,11 @@ */ package com.vitorpamplona.quartz.utils -import org.junit.Assert.assertEquals -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Test import kotlin.random.Random +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue class HexEncodingTest { val testHex = "48a72b485d38338627ec9d427583551f9af4f016c739b8ec0d6313540a8b12cf" @@ -41,16 +41,16 @@ class HexEncodingTest { @Test fun testIsHex() { - assertFalse("/0", Hex.isHex("/0")) - assertFalse("/.", Hex.isHex("/.")) - assertFalse("::", Hex.isHex("::")) - assertFalse("!!", Hex.isHex("!!")) - assertFalse("@@", Hex.isHex("@@")) - assertFalse("GG", Hex.isHex("GG")) - assertFalse("FG", Hex.isHex("FG")) - assertFalse("`a", Hex.isHex("`a")) - assertFalse("gg", Hex.isHex("gg")) - assertFalse("fg", Hex.isHex("fg")) + assertFalse(Hex.isHex("/0"), "/0") + assertFalse(Hex.isHex("/."), "/.") + assertFalse(Hex.isHex("::"), "::") + assertFalse(Hex.isHex("!!"), "!!") + assertFalse(Hex.isHex("@@"), "@@") + assertFalse(Hex.isHex("GG"), "GG") + assertFalse(Hex.isHex("FG"), "FG") + assertFalse(Hex.isHex("`a"), "`a") + assertFalse(Hex.isHex("gg"), "gg") + assertFalse(Hex.isHex("fg"), "fg") } @OptIn(ExperimentalStdlibApi::class) @@ -59,9 +59,9 @@ class HexEncodingTest { for (i in 0..10000) { val bytes = Random.nextBytes(32) val hex = bytes.toHexString(HexFormat.Default) - assertTrue(hex, Hex.isHex(hex)) + assertTrue(Hex.isHex(hex), hex) val hexUpper = bytes.toHexString(HexFormat.UpperCase) - assertTrue(hexUpper, Hex.isHex(hexUpper)) + assertTrue(Hex.isHex(hexUpper), hexUpper) } } diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/utils/SignerUtils.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/utils/SignerUtils.kt similarity index 100% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/utils/SignerUtils.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/utils/SignerUtils.kt diff --git a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/utils/StringUtilsTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/utils/StringUtilsTest.kt similarity index 93% rename from quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/utils/StringUtilsTest.kt rename to quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/utils/StringUtilsTest.kt index 5221b9947e..6e5d4df614 100644 --- a/quartz/src/androidUnitTest/kotlin/com/vitorpamplona/quartz/utils/StringUtilsTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/utils/StringUtilsTest.kt @@ -20,15 +20,15 @@ */ package com.vitorpamplona.quartz.utils -import junit.framework.TestCase -import org.junit.Test +import kotlin.test.Test +import kotlin.test.assertTrue class StringUtilsTest { private val test = """Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32. The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham. -""".intern() +""" val atTheMiddle = DualCase("Lorem Ipsum".lowercase(), "Lorem Ipsum".uppercase()) val atTheBeginning = DualCase("contrAry".lowercase(), "contrAry".uppercase()) @@ -45,18 +45,18 @@ The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for t @Test fun middleCaseOurs() { val list = listOf(atTheMiddle) - TestCase.assertTrue(test.containsAny(list)) + assertTrue(test.containsAny(list)) } @Test fun atTheBeginningOurs() { val list = listOf(atTheBeginning) - TestCase.assertTrue(test.containsAny(list)) + assertTrue(test.containsAny(list)) } @Test fun atTheEndOurs() { val list = listOf(atTheEndCase) - TestCase.assertTrue(test.containsAny(list)) + assertTrue(test.containsAny(list)) } } diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.ios.kt new file mode 100644 index 0000000000..521c0daddc --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.ios.kt @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.core + +import com.vitorpamplona.quartz.utils.bytesUsedInMemory +import com.vitorpamplona.quartz.utils.pointerSizeInBytes + +actual data class Address actual constructor( + actual val kind: Kind, + actual val pubKeyHex: HexKey, + actual val dTag: String, +) : Comparable
{ + actual fun toValue() = assemble(kind, pubKeyHex, dTag) + + actual fun countMemory(): Int = + 3 * pointerSizeInBytes + + 8 + // kind + pubKeyHex.bytesUsedInMemory() + + dTag.bytesUsedInMemory() + + actual override fun compareTo(other: Address): Int { + val result = kind.compareTo(other.kind) + return if (result == 0) { + val result2 = pubKeyHex.compareTo(other.pubKeyHex) + if (result2 == 0) { + dTag.compareTo(other.dTag) + } else { + result2 + } + } else { + result + } + } + + actual companion object { + actual fun assemble( + kind: Int, + pubKeyHex: HexKey, + dTag: String, + ) = AddressSerializer.assemble(kind, pubKeyHex, dTag) + + actual fun parse(addressId: String) = AddressSerializer.parse(addressId) + + actual fun isOfKind( + addressId: String, + kind: String, + ) = addressId.startsWith(kind) && addressId[kind.length] == ':' + } +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/OptimizedJsonMapper.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/OptimizedJsonMapper.ios.kt new file mode 100644 index 0000000000..c73cec34b0 --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/OptimizedJsonMapper.ios.kt @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.core + +actual object OptimizedJsonMapper { + actual fun fromJson(json: String): Event = TODO("Not yet implemented") + + actual fun toJson(event: Event): String = TODO("Not yet implemented") + + actual fun fromJsonToTagArray(json: String): Array> = TODO("Not yet implemented") + + actual fun toJson(tags: Array>): String = TODO("Not yet implemented") + + actual inline fun fromJsonTo(json: String): T = TODO("Not yet implemented") + + actual fun toJson(value: OptimizedSerializable): String = TODO("Not yet implemented") +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasherSerializer.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasherSerializer.ios.kt new file mode 100644 index 0000000000..ff745026f7 --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasherSerializer.ios.kt @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.crypto + +import com.vitorpamplona.quartz.nip01Core.core.HexKey + +actual object EventHasherSerializer { + actual fun makeJsonForId( + pubKey: HexKey, + createdAt: Long, + kind: Int, + tags: Array>, + content: String, + ): String { + TODO("Not yet implemented") + } + + actual fun fastMakeJsonForId( + pubKey: HexKey, + createdAt: Long, + kind: Int, + tags: Array>, + content: String, + ): ByteArray { + TODO("Not yet implemented") + } +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.ios.kt new file mode 100644 index 0000000000..8fe3954c20 --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.ios.kt @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2025 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.quartz.nip96FileStorage.info + +actual fun makeAbsoluteIfRelativeUrl( + baseUrl: String, + potentiallyRelativeUrl: String, +): String { + TODO("Not yet implemented") +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimal.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimal.kt new file mode 100644 index 0000000000..8ac830115b --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimal.kt @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import platform.Foundation.NSDecimalNumber + +// class from https://github.com/apollographql/apollo-kotlin-adapters +actual class BigDecimal internal constructor( + private val raw: NSDecimalNumber, +) : Number() { + actual constructor(strVal: String) : this(NSDecimalNumber(strVal)) + + actual constructor(doubleVal: Double) : this(NSDecimalNumber(doubleVal)) + + actual constructor(intVal: Int) : this(NSDecimalNumber(int = intVal)) + + actual constructor(longVal: Long) : this(NSDecimalNumber(longLong = longVal)) + + actual fun add(augend: BigDecimal): BigDecimal = BigDecimal(raw.decimalNumberByAdding(augend.raw)) + + actual fun subtract(subtrahend: BigDecimal): BigDecimal = BigDecimal(raw.decimalNumberBySubtracting(subtrahend.raw)) + + actual fun multiply(multiplicand: BigDecimal): BigDecimal = BigDecimal(raw.decimalNumberByMultiplyingBy(multiplicand.raw)) + + actual fun divide(divisor: BigDecimal): BigDecimal = BigDecimal(raw.decimalNumberByDividingBy(divisor.raw)) + + actual fun negate(): BigDecimal = BigDecimal(NSDecimalNumber(int = 0).decimalNumberBySubtracting(raw)) + + actual fun signum(): Int { + val result = raw.compare(NSDecimalNumber(int = 0)).toInt() + return when { + result < 0 -> -1 + result > 0 -> 1 + else -> 0 + } + } + + override fun toInt(): Int = raw.intValue + + override fun toLong(): Long = raw.longLongValue + + override fun toShort(): Short = raw.shortValue + + override fun toByte(): Byte = raw.charValue + + override fun toDouble(): Double = raw.doubleValue + + override fun toFloat(): Float = raw.floatValue + + override fun equals(other: Any?): Boolean = (this === other) || raw == (other as? BigDecimal)?.raw + + override fun hashCode(): Int = raw.hashCode() + + override fun toString(): String = raw.stringValue +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/BitSet.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/BitSet.ios.kt new file mode 100644 index 0000000000..0172dc0e05 --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/BitSet.ios.kt @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +actual class BitSet { + actual constructor(nBits: Int) { + TODO("Not yet implemented") + } + + actual fun set(bitIndex: Int) { + TODO("Not yet implemented") + } + + actual fun clear(bitIndex: Int) { + TODO("Not yet implemented") + } + + actual fun get(bitIndex: Int): Boolean { + TODO("Not yet implemented") + } + + actual fun size(): Int { + TODO("Not yet implemented") + } + + actual fun toByteArray(): ByteArray { + TODO("Not yet implemented") + } +} + +actual fun bitSetValueOf(bytes: ByteArray): BitSet { + TODO("Not yet implemented") +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/ICalendarAsyncSubmit.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/GZip.ios.kt similarity index 81% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/ICalendarAsyncSubmit.kt rename to quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/GZip.ios.kt index b80e2238d7..d8e12849b3 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/ICalendarAsyncSubmit.kt +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/GZip.ios.kt @@ -18,12 +18,14 @@ * 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.quartz.nip03Timestamp.ots +package com.vitorpamplona.quartz.utils -import java.util.Optional -import java.util.concurrent.Callable +actual object GZip { + actual fun compress(content: String): ByteArray { + TODO("Not yet implemented") + } -interface ICalendarAsyncSubmit : Callable> { - @Throws(Exception::class) - override fun call(): Optional + actual fun decompress(content: ByteArray): String { + TODO("Not yet implemented") + } } diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.ios.kt new file mode 100644 index 0000000000..b5ec2df1ab --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.ios.kt @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +actual object LibSodiumInstance { + actual fun cryptoAeadXChaCha20Poly1305IetfDecrypt( + message: ByteArray, + nSec: ByteArray, + ciphertext: ByteArray, + ad: ByteArray, + nPub: ByteArray, + k: ByteArray, + ): Boolean { + TODO("Not yet implemented") + } + + actual fun cryptoAeadXChaCha20Poly1305IetfEncrypt( + ciphertext: ByteArray, + message: ByteArray, + ad: ByteArray, + nSec: ByteArray, + nPub: ByteArray, + k: ByteArray, + ): Boolean { + TODO("Not yet implemented") + } + + actual fun cryptoStreamChaCha20IetfXor( + message: ByteArray, + nonce: ByteArray?, + key: ByteArray?, + ): ByteArray { + TODO("Not yet implemented") + } + + actual fun cryptoStreamXChaCha20Xor( + messageBytes: ByteArray, + nonce: ByteArray, + key: ByteArray, + ): ByteArray { + TODO("Not yet implemented") + } +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Log.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Log.ios.kt new file mode 100644 index 0000000000..97af02c5bb --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Log.ios.kt @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import platform.Foundation.NSLog + +actual object Log { + actual fun w( + tag: String, + message: String, + throwable: Throwable?, + ) { + if (throwable != null) { + NSLog("WARN: [$tag] $message. Throwable: $throwable CAUSE ${throwable.cause}") + } else { + NSLog("WARN: [$tag] $message") + } + } + + actual fun e( + tag: String, + message: String, + throwable: Throwable?, + ) { + if (throwable != null) { + NSLog("ERROR: [$tag] $message. Throwable: $throwable CAUSE ${throwable.cause}") + } else { + NSLog("ERROR: [$tag] $message") + } + } + + actual fun d( + tag: String, + message: String, + ) { + NSLog("DEBUG: [$tag] $message") + } + + actual fun i( + tag: String, + message: String, + ) { + NSLog("INFO: [$tag] $message") + } +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Platform.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Platform.ios.kt new file mode 100644 index 0000000000..76c8b72b64 --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Platform.ios.kt @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +// iosMain +import platform.Foundation.NSDate +import platform.Foundation.timeIntervalSince1970 + +actual fun platform() = "iOS" + +actual fun currentTimeSeconds(): Long { + // CFAbsoluteTimeGetCurrent() returns seconds since 2001-01-01 00:00:00 UTC + // NSDate().timeIntervalSince1970 returns seconds since 1970-01-01 00:00:00 UTC + return (NSDate().timeIntervalSince1970).toLong() +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Rfc3986.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Rfc3986.ios.kt new file mode 100644 index 0000000000..1444daffdc --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Rfc3986.ios.kt @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +actual object Rfc3986 { + actual fun normalize(uri: String): String = TODO() + + actual fun isValidUrl(url: String): Boolean = TODO() + + actual fun normalizeAndRemoveFragment(url: String): String = TODO() + + actual fun host(url: String): String = TODO() +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.ios.kt new file mode 100644 index 0000000000..c08d8edef0 --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.ios.kt @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +actual object Secp256k1Instance { + actual fun compressedPubKeyFor(privKey: ByteArray): ByteArray { + TODO("Not yet implemented") + } + + actual fun isPrivateKeyValid(il: ByteArray): Boolean { + TODO("Not yet implemented") + } + + actual fun signSchnorr( + data: ByteArray, + privKey: ByteArray, + nonce: ByteArray?, + ): ByteArray { + TODO("Not yet implemented") + } + + actual fun signSchnorr( + data: ByteArray, + privKey: ByteArray, + ): ByteArray { + TODO("Not yet implemented") + } + + actual fun verifySchnorr( + signature: ByteArray, + hash: ByteArray, + pubKey: ByteArray, + ): Boolean { + TODO("Not yet implemented") + } + + actual fun privateKeyAdd( + first: ByteArray, + second: ByteArray, + ): ByteArray { + TODO("Not yet implemented") + } + + actual fun pubKeyTweakMulCompact( + pubKey: ByteArray, + privateKey: ByteArray, + ): ByteArray { + TODO("Not yet implemented") + } +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.ios.kt new file mode 100644 index 0000000000..5029a922e2 --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.ios.kt @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.refTo +import platform.Security.SecRandomCopyBytes +import platform.Security.kSecRandomDefault + +actual class SecureRandom { + actual fun nextInt(bound: Int): Int { + require(bound > 0) { throw IllegalArgumentException("Bad Bound $bound") } + + var intValue = nextPositiveInt() + + val m = bound - 1 + if ((bound and m) == 0) { + // i.e., bound is a power of 2 + intValue = ((bound * intValue.toLong()) shr 31).toInt() + } else { // reject over-represented candidates + var u: Int = intValue + intValue = u % bound + while (u - intValue + m < 0) { + u = nextPositiveInt() + intValue = u % bound + } + } + + return intValue + } + + fun nextPositiveInt(): Int { + val bytes = ByteArray(4) + nextBytes(bytes) + val value = + ((bytes[0].toInt() and 0xFF) shl 24) or + ((bytes[1].toInt() and 0xFF) shl 16) or + ((bytes[2].toInt() and 0xFF) shl 8) or + (bytes[3].toInt() and 0xFF) + return if (value > 0) { + value + } else { + -value + } + } + + @OptIn(ExperimentalForeignApi::class) + actual fun nextBytes(output: ByteArray) { + val status = SecRandomCopyBytes(kSecRandomDefault, output.size.toULong(), output.refTo(0)) + if (status != 0) { + // Handle error, e.g., throw an exception + throw IllegalStateException("Failed to generate secure random bytes: $status") + } + } +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/StringExt.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/StringExt.ios.kt new file mode 100644 index 0000000000..048224352c --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/StringExt.ios.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +actual fun String.internIfPossible(): String = this diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/URLs.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/URLs.ios.kt new file mode 100644 index 0000000000..51e91a7066 --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/URLs.ios.kt @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +actual fun fastFindURLs(text: String): List { + TODO("Not yet implemented") +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/UnicodeNormalizer.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/UnicodeNormalizer.ios.kt new file mode 100644 index 0000000000..dd5b77b6ea --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/UnicodeNormalizer.ios.kt @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +actual class UnicodeNormalizer { + actual fun normalizeNFKC(input: String): String { + TODO("Not yet implemented") + } +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.ios.kt new file mode 100644 index 0000000000..2509816506 --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.ios.kt @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import platform.Foundation.NSURLComponents +import platform.Foundation.NSURLQueryItem + +actual class UriParser actual constructor( + uri: String, +) { + private val nsUrlComponents: NSURLComponents? = NSURLComponents(string = uri) + + actual fun scheme(): String? = nsUrlComponents?.scheme + + actual fun host(): String? = nsUrlComponents?.host + + actual fun port(): Int? { + // The NSNumber?.intValue is a way to handle a nullable port and convert it + // from a platform-specific number type to a Kotlin Int. + return nsUrlComponents?.port?.intValue + } + + actual fun path(): String? = nsUrlComponents?.path + + actual fun queryParameterNames(): Set { + val queryItems = nsUrlComponents?.queryItems ?: return emptySet() + return queryItems.mapNotNull { (it as? NSURLQueryItem)?.name }.toSet() + } + + actual fun getQueryParameter(param: String): String? { + val queryItems = nsUrlComponents?.queryItems ?: return null + return (queryItems.firstOrNull { (it as? NSURLQueryItem)?.name == param } as? NSURLQueryItem)?.value + } + + val fragments: Map by lazy { + nsUrlComponents?.fragment()?.ifBlank { null }?.let { keyValuePair -> + keyValuePair.split('&').associate { paramValue -> + val parts = paramValue.split("=", limit = 2) + if (parts.size == 2) { + parts[0] to parts[1] + } else { + parts[0] to "" // Handle parameters without a value, e.g., "param&other=value" + } + } + } ?: emptyMap() + } + + actual fun fragments(): Map = fragments +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/UrlEncoder.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/UrlEncoder.ios.kt new file mode 100644 index 0000000000..9312110888 --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/UrlEncoder.ios.kt @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +actual object UrlEncoder { + actual fun encode(value: String): String { + TODO("Not yet implemented") + } + + actual fun decode(value: String): String { + TODO("Not yet implemented") + } +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.ios.kt new file mode 100644 index 0000000000..6d5910ad72 --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.ios.kt @@ -0,0 +1,160 @@ +/** + * Copyright (c) 2025 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.quartz.utils.cache + +// Need of find a Concurrent/ThreadSafe HashMap in iOS +actual class LargeCache : ICacheOperations { + actual fun keys(): Set { + TODO("Not yet implemented") + } + + actual fun values(): Iterable { + TODO("Not yet implemented") + } + + actual fun get(key: K): V? { + TODO("Not yet implemented") + } + + actual fun remove(key: K): V? { + TODO("Not yet implemented") + } + + actual fun isEmpty(): Boolean { + TODO("Not yet implemented") + } + + actual fun clear() { + } + + actual fun containsKey(key: K): Boolean { + TODO("Not yet implemented") + } + + actual fun put( + key: K, + value: V, + ) { + } + + actual fun getOrCreate( + key: K, + builder: (K) -> V, + ): V { + TODO("Not yet implemented") + } + + actual fun createIfAbsent( + key: K, + builder: (K) -> V, + ): Boolean { + TODO("Not yet implemented") + } + + actual override fun size(): Int { + TODO("Not yet implemented") + } + + actual override fun forEach(consumer: ICacheBiConsumer) { + TODO("Not yet implemented") + } + + actual override fun filter(consumer: CacheCollectors.BiFilter): List { + TODO("Not yet implemented") + } + + actual override fun filterIntoSet(consumer: CacheCollectors.BiFilter): Set { + TODO("Not yet implemented") + } + + actual override fun map(consumer: CacheCollectors.BiNotNullMapper): List { + TODO("Not yet implemented") + } + + actual override fun mapNotNull(consumer: CacheCollectors.BiMapper): List { + TODO("Not yet implemented") + } + + actual override fun mapNotNullIntoSet(consumer: CacheCollectors.BiMapper): Set { + TODO("Not yet implemented") + } + + actual override fun mapFlatten(consumer: CacheCollectors.BiMapper?>): List { + TODO("Not yet implemented") + } + + actual override fun mapFlattenIntoSet(consumer: CacheCollectors.BiMapper?>): Set { + TODO("Not yet implemented") + } + + actual override fun maxOrNullOf( + filter: CacheCollectors.BiFilter, + comparator: Comparator, + ): V? { + TODO("Not yet implemented") + } + + actual override fun sumOf(consumer: CacheCollectors.BiSumOf): Int { + TODO("Not yet implemented") + } + + actual override fun sumOfLong(consumer: CacheCollectors.BiSumOfLong): Long { + TODO("Not yet implemented") + } + + actual override fun groupBy(consumer: CacheCollectors.BiNotNullMapper): Map> { + TODO("Not yet implemented") + } + + actual override fun countByGroup(consumer: CacheCollectors.BiNotNullMapper): Map { + TODO("Not yet implemented") + } + + actual override fun sumByGroup( + groupMap: CacheCollectors.BiNotNullMapper, + sumOf: CacheCollectors.BiNotNullMapper, + ): Map { + TODO("Not yet implemented") + } + + actual override fun count(consumer: CacheCollectors.BiFilter): Int { + TODO("Not yet implemented") + } + + actual override fun associate(transform: (K, V) -> Pair): Map { + TODO("Not yet implemented") + } + + actual override fun associateWith(transform: (K, V) -> U?): Map { + TODO("Not yet implemented") + } + + actual override fun joinToString( + separator: CharSequence, + prefix: CharSequence, + postfix: CharSequence, + limit: Int, + truncated: CharSequence, + transform: ((K, V) -> CharSequence)?, + ): String { + TODO("Not yet implemented") + } +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESCBC.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESCBC.ios.kt new file mode 100644 index 0000000000..4eda0ea287 --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESCBC.ios.kt @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2025 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.quartz.utils.ciphers + +actual class AESCBC actual constructor( + actual val keyBytes: ByteArray, + actual val iv: ByteArray, +) : NostrCipher { + actual override fun name(): String { + TODO("Not yet implemented") + } + + actual override fun encrypt(bytesToEncrypt: ByteArray): ByteArray { + TODO("Not yet implemented") + } + + actual override fun decrypt(bytesToDecrypt: ByteArray): ByteArray { + TODO("Not yet implemented") + } + + actual override fun decryptOrNull(bytesToDecrypt: ByteArray): ByteArray? { + TODO("Not yet implemented") + } +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.ios.kt new file mode 100644 index 0000000000..a3b3265149 --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.ios.kt @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2025 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.quartz.utils.ciphers + +actual class AESGCM actual constructor( + actual val keyBytes: ByteArray, + actual val nonce: ByteArray, +) : NostrCipher { + actual override fun name(): String { + TODO("Not yet implemented") + } + + actual override fun encrypt(bytesToEncrypt: ByteArray): ByteArray { + TODO("Not yet implemented") + } + + actual override fun decrypt(bytesToDecrypt: ByteArray): ByteArray { + TODO("Not yet implemented") + } + + actual override fun decryptOrNull(bytesToDecrypt: ByteArray): ByteArray? { + TODO("Not yet implemented") + } +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/diggest/DigestInstance.ios.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/diggest/DigestInstance.ios.kt new file mode 100644 index 0000000000..223dcf98cd --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/diggest/DigestInstance.ios.kt @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2025 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.quartz.utils.diggest + +actual class DigestInstance actual constructor( + algorithm: String, +) { + actual fun update(array: ByteArray) { + TODO("Not yet implemented") + } + + actual fun update(byte: Byte) { + TODO("Not yet implemented") + } + + actual fun digest(): ByteArray { + TODO("Not yet implemented") + } + + actual fun digest(input: ByteArray): ByteArray { + TODO("Not yet implemented") + } +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/mac/MacInstance.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/mac/MacInstance.kt new file mode 100644 index 0000000000..0f5b326a4f --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/mac/MacInstance.kt @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2025 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.quartz.utils.mac + +actual class MacInstance actual constructor( + algorithm: String, + key: ByteArray, +) { + actual fun init( + key: ByteArray, + algorithm: String, + ) { + TODO("Not yet implemented") + } + + actual fun getMacLength(): Int { + TODO("Not yet implemented") + } + + actual fun update(array: ByteArray) { + TODO("Not yet implemented") + } + + actual fun update(byte: Byte) { + TODO("Not yet implemented") + } + + actual fun doFinal(): ByteArray { + TODO("Not yet implemented") + } + + actual fun doFinal( + output: ByteArray, + offset: Int, + ) { + TODO("Not yet implemented") + } +} diff --git a/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.kt b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.kt new file mode 100644 index 0000000000..9aaaa1dbbd --- /dev/null +++ b/quartz/src/iosMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.kt @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2025 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.quartz.utils.sha256 + +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.addressOf +import kotlinx.cinterop.convert +import kotlinx.cinterop.usePinned +import platform.CoreCrypto.CC_SHA256 +import platform.CoreCrypto.CC_SHA256_DIGEST_LENGTH + +@OptIn(ExperimentalForeignApi::class) +actual fun sha256(data: ByteArray): ByteArray { + val digest = UByteArray(CC_SHA256_DIGEST_LENGTH) + + data.usePinned { inputPinned -> + digest.usePinned { digestPinned -> + CC_SHA256( + inputPinned.addressOf(0), + data.size.convert(), + digestPinned.addressOf(0), + ) + } + } + + return digest.toByteArray() +} diff --git a/quartz/src/iosTest/kotlin/com/vitorpamplona/quartz/TestResourceLoader.kt b/quartz/src/iosTest/kotlin/com/vitorpamplona/quartz/TestResourceLoader.kt new file mode 100644 index 0000000000..e9ff8dd5bf --- /dev/null +++ b/quartz/src/iosTest/kotlin/com/vitorpamplona/quartz/TestResourceLoader.kt @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2025 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.quartz + +import kotlinx.cinterop.BetaInteropApi +import kotlinx.cinterop.ExperimentalForeignApi +import platform.Foundation.NSBundle +import platform.Foundation.NSString +import platform.Foundation.NSUTF8StringEncoding +import platform.Foundation.stringWithContentsOfFile +import platform.darwin.NSObject +import platform.darwin.NSObjectMeta + +actual class TestResourceLoader { + @OptIn(ExperimentalForeignApi::class, BetaInteropApi::class) + actual fun loadString(file: String): String { + val bundle = NSBundle.Companion.bundleForClass(BundleMarker) + val path = + bundle.pathForResource(file, ofType = null) + ?: throw IllegalArgumentException("Resource not found: $file") + return NSString.Companion.stringWithContentsOfFile(path, encoding = NSUTF8StringEncoding, error = null)!! + } + + private class BundleMarker : NSObject() { + companion object : NSObjectMeta() + } +} diff --git a/quartz/src/iosTest/resources/relayDB.txt b/quartz/src/iosTest/resources/relayDB.txt new file mode 100644 index 0000000000..0977f44b3a --- /dev/null +++ b/quartz/src/iosTest/resources/relayDB.txt @@ -0,0 +1,2539 @@ +wss://nostr.wine +wss://relay.orangepill.dev +wss://xmr.usenostr.org +wss://nostr.portemonero.com +wss://nostr.xmr.rocks +wss://relay.nostr.band +wss://filter.nostr.wine +wss://nostr.milou.lol +wss://nostr.mutinywallet.com +wss://nostr-pub.wellorder.net +wss://nostr.zebedee.cloud +wss://nos.lol +wss://brb.io +wss://bitcoiner.social +wss://nostr.decentony.com +wss://relay.nostriches.org +wss://paid.spore.ws +wss://eden.nostr.land +wss://puravida.nostr.land +wss://5dzvuefllevkhk7miqynaviguedxfnofrayu2xwfwtlkdg4radjdlyqd.onion +wss://relay-jp.nostr.wirednet.jp +wss://relay.nostrich.land +wss://nostr.holybea.com +wss://nostr-relay.nokotaro.com +wss://nostr-paid.h3z.jp +wss://nostrja-kari.heguro.com +wss://nostr.mom +wss://nostr.fediverse.jp +wss://nostr.h3z.jp +wss://universe.nostrich.land +wss://nostr.uselessshit.co +wss://atlas.nostr.land +wss://relay.snort.social +wss://universe.nostrich.landlangenlanges +wss://nostr.slothy.win +wss://nostr.plebchain.org +wss://nostr-relay.untethr.me +wss://relay.nostr.com.au +wss://nostr.inosta.cc +wss://relay.nostrati.com +wss://nostr.bitcoiner.social +wss://relay.nostrplebs.com +wss://relay.nostr.info +wss://nostr-relay.wlvs.space +wss://nostr.oxtr.dev +wss://nostr.onsats.org +wss://relay.wellorder.net +wss://relay.plebstr.com +wss://no.str.cr +wss://nostr.walletofsatoshi.com +wss://nostr.mwmdev.com +wss://relay.nostr.bg +wss://nostr.rocks +wss://nostr.fmt.wiz.biz +wss://nostr.orangepill.dev +wss://nostr-pub.semisol.dev +wss://nostr.sandwich.farm +wss://relay.nostr.ch +wss://relay.orange-crush.com +wss://private.red.gb.net +wss://nostr.lnprivate.network +wss://nostr.lu.ke +wss://relay.nostr.wirednet.jp +wss://lightningrelay.com +wss://relay.nostrgraph.net +wss://relay.nostrica.com +wss://relay.mostr.pub +wss://nostr-sg.com +wss://nostr.zkid.social +wss://relay.nostr.vet +wss://relay.nostr3.io +wss://relay.arsip.my.id +wss://relay.current.fyi +wss://global.relay.red +wss://nostr.island.network +wss://node01.nostress.cc +wss://relay.nostr.net.in +wss://relay.utxo.one +wss://relay-1.arsip.my.id +wss://nostrical.com +wss://nostro.cc +wss://rsslay.nostr.moe +wss://relay.nostr.or.jp +wss://nostream.unift.xyz +wss://blastr.f7z.xyz +wss://relay.honk.pw +wss://universe.nostrich.landlangja +wss://nostream.ocha.one +wss://paid-relay.nost.love +wss://offchain.pub +wss://nostr-usa.ka1gbeoa21bnm.us-west-2.cs.amazonlightsail.com +wss://nostr.terminus.money +wss://nostr.shawnyeager.net +wss://public.nostr.swissrouting.com +wss://nostrex.fly.dev +wss://relay.727whisky.com +wss://relay.cryptocculture.com +wss://relay.bleskop.com +wss://nostr.lorentz.is +wss://nostr.actn.io +wss://nostr-relay.lnmarkets.com +wss://nostr.openchain.fr +wss://relay.punkhub.me +wss://nostr.blipme.app +wss://nostr.swiss-enigma.ch +wss://nostr-verified.wellorder.net +wss://at.nostrworks.com +wss://21sats.net +wss://e.nos.lol +wss://nostr.mikedilger.com +wss://nostr.azte.co +wss://noster.bitcoiner.social +wss://relay.nostr.moe +wss://nostream.nostrly.io +wss://nostr.gives.africa +wss://nostr.21sats.net +wss://bitcoinmaximalists.online +wss://paid.nostrified.org +wss://nostr.1sat.org +wss://nostr.relayer.se +wss://sg.qemura.xyz +wss://nostr.coinos.io +wss://nostr.bitcoinplebs.de +wss://nostrich.friendship.tw +wss://nostr.sg +wss://eosla.com +wss://nostr.sidnlabs.nl +wss://nostr.foundrydigital.com +wss://relay.nostrview.com +wss://nostr.semisol.dev +wss://relay.f7z.io +wss://wlvs.space +wss://nostr.v0l.io +wss://nostr-relay.digitalmob.ro +wss://rsslay.fiatjaf.com +wss://relay.theorangepillapp.com +wss://relay.zeh.app +wss://nostr.zoomout.chat +wss://relay.stoner.com +wss://nostr.cercatrova.me +wss://relay.ryzizub.com +wss://nostr-1.nbo.angani.co +wss://nostr21.com +wss://spore.ws +wss://nostrue.com +wss://no-str.org +wss://relay.taxi +wss://ragnar-relay.com +wss://relay.austrich.net +wss://relay.nostr-latam.link +wss://1.noztr.com +wss://relay.nostr.scot +wss://test.relay.nostrich.day +wss://jiggytom.ddns.net +wss://nostr.bongbong.com +wss://relay.nostromo.social +wss://relay.sendstr.com +wss://nostr-dev.universalname.space +wss://relay.nostrcheck.me +wss://nostr.libertasprimordium.com +wss://nostr.kollider.xyz +wss://expensive-relay.fiatjaf.com +wss://nostr-sandbox.minds.io +wss://relay.nostrich.de +wss://nostr.gromeul.eu +wss://relay.nostr.wine +wss://nostr.screaminglife.io +wss://nostr-relay.derekross.me +wss://nostrica.nostrnotes.com +wss://paid.no.str.cr +wss://nostr.sethforprivacy.com +wss://nostr.dumpit.top +wss://nostr.herci.one +wss://cheery-paddock-rsakdrtc35c55n6yregn.wnext.app +wss://nostr.blockpower.capital +wss://nostr.nym.life +wss://nostr-verif.slothy.win +wss://fiatdenier.com +wss://nostr.bitcoin-21.org +wss://nostr.fluidtrack.in +wss://nostr.developer.li +wss://r.ayit.org +wss://relay.nostr.nu +wss://nostr.bostonbtc.com +wss://rly.social +wss://nostr.bridgey.dev +wss://relay.nostrprotocol.net +wss://nostr.mado.io +wss://nostr.einundzwanzig.space +wss://nostr2.actn.io +wss://nostr-relay.freedomnode.com +wss://nostr.pleb.network +wss://nostr.mouton.dev +wss://eelay.current.fyi +wss://nostr.notmyhostna.me +wss://nostr.pjv.me +wss://nostr.jatm.link +wss://nostr.fractalized.ovh +wss://nostr-relay.app.ikeji.ma +wss://relayer.ocha.one +wss://nostr.com.de +wss://nostr-2.afarazit.eu +wss://nostr.l00p.org +wss://nostr.drss.io +wss://relay.nostrify.io +wss://nostr.radixrat.com +wss://nostr-relay.bitcoin.ninja +wss://nostrsatva.net +wss://nostr.mustardnodes.com +wss://nostr01.vida.dev +wss://nostr.noones.com +wss://nostr.easify.de +wss://nostr3.actn.io +wss://moonbreeze.richardbondi.net +wss://nostr.naut.social +wss://private-nostr.v0l.io +wss://nostr.zaprite.io +wss://nostr.lightninglinks.xyz +wss://nostr.hackerman.pro +wss://nr.yay.so +wss://nostr.roundrockbitcoiners.com +wss://nostr.sovbit.host +wss://nostrelay.yeghro.site +wss://pow32.nostr.land +wss://nostr.1729.cloud +wss://nostr.rdfriedl.com +wss://nostr.h4x0r.host +wss://nostr.up.railway.app +wss://nostr.lnorb.com +wss://nostr.lordkno.ws +wss://relay.nostr.vision +wss://nostr-3.orba.ca +wss://satstacker.cloud +wss://freedom-relay.herokuapp.com +wss://nostr-relay.freeberty.net +wss://nostr.unknown.place +wss://nostr.delo.software +wss://relay.nostr.pro +wss://relay.minds.com +wss://nostr.ono.re +wss://relay.grunch.dev +wss://relay.cynsar.foundation +wss://relay.oldcity-bitcoiners.info +wss://relay.bitid.nz +wss://relay.nostr.xyz +wss://relay.futohq.com +wss://relay.farscapian.com +wss://astral.ninja +wss://relay.sovereign-stack.org +wss://nostr-2.zebedee.cloud +wss://nostr.nymsrelay.com +wss://relay.kronkltd.net +wss://relay.r3d.red +wss://universe.nostrich.landlangen +wss://nostr-dev.wellorder.net +wss://nostr.beta3.dev +wss://nostr.data.haus +wss://nostr.hugo.md +wss://relay-dev.cowdle.gg +wss://relay.dwadziesciajeden.pl +wss://tmp-relay.cesc.trade +wss://nostr.massmux.com +wss://relay.nostr.africa +wss://nostr1.tunnelsats.com +wss://nostr.f44.dev +wss://relay.n057r.club +wss://nostr-verif.slothy.com +wss://nostr.1f52b.xyz +wss://nostr.sebastix.dev +wss://nostr.lightning.contact +wss://nostr.rly.social +wss://noster.online +wss://relay.lexingtonbitcoin.org +wss://nostr.bitcoinbay.engineering +wss://nostr.howtobitcoin.shop +wss://blg.nostr.sx +wss://deschooling.us +wss://foolay.nostr.moe +wss://freespeech.casa +wss://nostr-01.bolt.observer +wss://nostr-01.dorafactory.org +wss://nostr-au.coinfundit.com +wss://nostr-eu.coinfundit.com +wss://nostr-relay.alekberg.net +wss://nostr-pub1.southflorida.ninja +wss://nostr-relay.gkbrk.com +wss://nostr-relay.pcdkd.fyi +wss://nostr-relay.schnitzel.world +wss://nostr-us.coinfundit.com +wss://nostr.21crypto.ch +wss://nostr.600.wtf +wss://nostr.8e23.net +wss://nostr.app.runonflux.io +wss://nostr.arguflow.gg +wss://nostr.bch.ninja +wss://nostr.chainofimmortals.net +wss://nostr.cizmar.net +wss://nostr.cheeserobot.org +wss://nostr.coollamer.com +wss://nostr.corebreach.com +wss://nostr.cro.social +wss://nostr.easydns.ca +wss://nostr.globals.fans +wss://nostr.handyjunky.com +wss://nostr.itas.li +wss://nostr.sectiontwo.org +wss://nostr.spleenrider.one +wss://nostr.thibautrey.fr +wss://nostr.uthark.com +wss://nostr.vulpem.com +wss://nostr.w3ird.tech +wss://nostr.whoop.ph +wss://nostr.yuv.al +wss://nostr01.opencult.com +wss://nostre.cc +wss://nostream.denizenid.com +wss://nostring.deno.dev +wss://pow.nostrati.com +wss://relay-pub.deschooling.us +wss://nostr.jiashanlu.synology.me +wss://nostr.klabo.blog +wss://relay.valireum.net +wss://nostr.fly.dev +wss://nostr.nordlysln.net +wss://nostr.zerofeerouting.com +wss://rsslay.nostr.net +wss://nostr-relay.nonce.academy +wss://nostr.rewardsbunny.com +wss://lv01.tater.ninja +wss://nostr-2.orba.ca +wss://nostr.orba.ca +wss://nostr.supremestack.xyz +wss://nostrrelay.com +wss://relay.nostr.au +wss://nostr.oooxxx.ml +wss://nostr.yael.at +wss://nostr-relay.trustbtc.org +wss://nostr.namek.link +wss://nostr-relay.wolfandcrow.tech +wss://nostr.satsophone.tk +wss://relay.dev.kronkltd.net +wss://nostr2.namek.link +wss://relay.21spirits.io +wss://relay.minds.io +wss://nostr.d11n.net +wss://nostr.tunnelsats.com +wss://nostr.leximaster.com +wss://mule.platanito.org +wss://nostr.robotechy.com +wss://relay.nostrmoto.xyz +wss://relay.boring.surf +wss://nostr.gruntwerk.org +wss://nostr.hyperlingo.com +wss://nostr.ethtozero.fr +wss://nostr.nodeofsven.com +wss://nostr.jimc.me +wss://nostr.utxo.lol +wss://relay.nyx.ma +wss://nostr.shmueli.org +wss://wizards.wormrobot.org +wss://nostr.sovbit.com +wss://nostr.datamagik.com +wss://relay.nostrid.com +wss://nostr1.starbackr.me +wss://relay.nostr.express +wss://nostr.formigator.eu +wss://nostr.xpersona.net +wss://nostr.digitalreformation.info +wss://nostr-relay.usebitcoin.space +wss://nostr-alpha.gruntwerk.org +wss://nostr-relay.australiaeast.cloudapp.azure.com +wss://nostr-relay.smoove.net +wss://nostr-relay.j3s7m4n.com +wss://nostr.demovement.net +wss://nostr.thesimplekid.com +wss://nostr.aozing.com +wss://nostr.blocs.fr +wss://no.str.watch +wss://btc.klendazu.com +wss://nostr.mrbits.it +wss://nostr.zenon.wtf +wss://no.contry.xyz +wss://nostream.gromeul.eu +wss://relay.nostr.ro +wss://nostr.ncsa.illinois.edu +wss://nostr.itssilvestre.com +wss://nostr.chaker.net +wss://knostr.neutrine.com +wss://nostr.pobblelabs.org +wss://nostr.simatime.com +wss://relay.nosphr.com +wss://student.chadpolytechnic.com +wss://nostr.localhost.re +wss://nostr.coinsamba.com.br +wss://deconomy-netser.ddns.net:2121 +wss://nostr.21m.fr +wss://zur.nostr.sx +wss://nostr-relay.texashedge.xyz +wss://spleenrider.herokuapp.com +wss://nostr.bitcoin.sex +wss://relay.nostrzoo.com +wss://nostr.blockchaincaffe.it +wss://nostr-bg01.ciph.rs +wss://knostr.neutrine.com:8880 +wss://nostr.ahaspharos.de +wss://nostr.argdx.net +wss://nostr.snblago.com +wss://merrcurr.up.railway.app +wss://nostr.bingtech.tk +wss://relay.nostr.wf +wss://relay.koreus.social +wss://nostr.randomdevelopment.biz +wss://relay.nostr.hu +wss://relay.nostr.lu +wss://relay.nostr.ae +wss://middling.myddns.me:8080 +wss://nostr.nikolaj.online +wss://relay.nostrology.org +wss://nostr.satoshi.fun +wss://nostream.kinchie.snowinning.com +wss://nostr.lapalomilla.mx +wss://relay.thes.ai +wss://rsr.uyky.net:30443 +wss://nostrafrica.pcdkd.fyi +wss://nostr.bitcoin-basel.ch +wss://relay.21baiwan.com +wss://nostr.ddns.net:8008 +wss://free-relay.nostrich.land +wss://nostr.lukeacl.com +wss://nostr.ddns.net +wss://nostr.rocket-tech.net +wss://nostr-1.afarazit.eu +wss://nostr.0nyx.eu +wss://nostr-mv.ashiroid.com +wss://lbrygen.xyz +wss://nostr.community.networks.deavmi.assigned.network +wss://nostr.ownscale.org +wss://relay1.gems.xyz +wss://nostr.soscary.net +wss://nostr.0xtr.dev +wss://damus.io +wss://relay.alien.blue +wss://nostr.btcmp.com +wss://relayer.fiatjaf.com +wss://relay.lacosanostr.com +wss://adult.18plus.social +wss://nostrrr.bublina.eu.org +wss://relay.stoner +wss://nostr.pwnshop.cloud +wss://nostr.directory +wss://nostr-relay-dev.wlvs.space +wss://member.cash +wss://relay.nyc1.vinux.app +wss://nostr-relay.digitamob.ro +wss://nor.st +wss://nostr.topeth.info +wss://nostr.rocketstyle.com.au +wss://relay.tnano.duckdns.org +wss://nostr.21l.st +wss://electra.nostr.land +wss://relay.codl.co +wss://nostr.koning-degraaf.nl +wss://relay.mrjohnsson.net +wss://nostr.thank.eu +wss://relay.stonez.me +wss://relay.nostr.distrl.net +wss://relay.valera.co +wss://api.semisol.dev +wss://nostr.lol +wss://relay.shitforce.one +wss://n-word.sharivegas.com +wss://lamp.wtf +wss://nostr.bitcoinpuertori.co +wss://nostr-01.bolt.oberver +wss://3d515c5277e9.ngrok.io +wss://nostr.xmrk.mooo.com +wss://alphapanda.pro +wss://relays.world +wss://universe.nostrich.landlangzh +wss://arnostr.permadao.io +wss://relay.chenxixian.cn +wss://universe.nostrich.landlangzhlangen +wss://v2r.chenxixian.cn +wss://nostr-relay-test.nokotaro.work +wss://universe.nostrich.landlangjalangen +wss://nostr.risa.zone +wss://relay.nosbin.com +wss://translate.argosopentech.com +wss://edennostr.land +wss://nostr.kawagarbo.xyz +wss://nostr.member.cash +wss://ch1.duno.com +wss://nostream-production-b80e.up.railway.app +wss://relay1.nostrich.cloud +wss://relay.t5y.ca +wss://nostr.zhongwen.world +wss://nostr.p2sh.co +wss://nostr.thomascdnns.com +wss://nostream.simon.snowinning.com +wss://relay.nostr.blockhenge.com +wss://nostr.buythisdip.com +wss://nostrua.com +wss://relay.bigred.social +wss://lingoh.dev +wss://nostr.poster.place +wss://nostr.geekgalaxy.com +wss://oarnx6xdrq5mygfdrbmzsvh3is3holefpz2x4qwbopwcicwd63gcivid.onion +wss://relay.nostropolis.xyz +wss://nostream-production-ba43.up.railway.app +wss://nostr.sabross.xyz +wss://relay.nvote.co +wss://nostrati.com +wss://cloudnull.land +wss://nostr.frennet.xyz +wss://nostr.wine.com +wss://nostr.sactiontwo.org +wss://nostr.liberty.fans +wss://nostr.primz.org +wss://btc-italia.online +wss://homenode.local:4848 +wss://nostr.frennet.xyzl +wss://relay.roosoft.com +wss://rasca.asnubes.art +wss://nostr.bitcoin.sexanewlycre +wss://nostr.barf.bz +wss://nostr.middling.mydns.jp +wss://relay.xuzmail.com +wss://no-str.wnhefei.cn:28443 +wss://quirky-bunch-isubghsvoi26fbbt3n7o.wnext.app +wss://nostr.fennel.org:7000 +wss://nostr.0ne.day +wss://nostr.vpn1.codingmerc.com +wss://nostr.jacany.com +wss://nostream.lucas.snowinning.com +wss://relay.beta.fogtype.com +wss://nostr.zue.news +wss://nostream.madbean.snowinning.com +wss://nostr2.rbel.co +wss://relay.1bps.io +wss://nostream-relay-nostr.831.pp.ua +wss://zee-relay.fly.dev +wss://nostrrelay.geforcy.com +wss://relay.nostr.jhot.me +wss://nostr.itredneck.com +wss://nostr.h3y6e.com +wss://relay.bitcoiner.social +wss://hos.lol +wss://iris.to +wss://nostr-pub.senisol.dev +wss://nostr-pub.wellirder.net +wss://bitcoinforthe.lol +wss://relav.nostr.info +wss://3e32-200-229-144-129.ngrok.io +wss://nostr-relay.hzrd149.com +wss://nostr-world.h3z.jp +wss://nostr.thesamecat.io +wss://nostr.compile-error.net +wss://relayable.org +wss://mostra.milou.lol +wss://nproxy.cc +wss://nostr.bitmatk.io +wss://coracle.social +wss://umbrel.local:4848 +wss://nostr.ownbtc.online +wss://wss.nostrgram.co:444 +wss://nostr.minimue81.selfhost.co +wss://relay.current.fy +wss://nostream.nostr.parts +wss://nostr.zebede.cloud +wss://nostrwhoop.ph +wss://relay.nostrified.org +wss://nproxy.zerologin.co +wss://nostr.pcdkd.fyi +wss://relay.kongerik.et +wss://nostr.eden.land +wss://nostr.retroware.run.place +wss://relay.humanumest.social +wss://bhagos.org +wss://hushvault.ie +wss://nostream-production-9458.up.railway.app +wss://nostr.nakamotosatoshi.cf +wss://globals.fans +wss://nostr.cruncher.com +wss://nostr.global.fan +wss://relay.nostr.snblago.com +wss://nostr.nokotaro.com +wss://ostr-1.afarazit.eu +wss://relay.zhix.in +wss://stats.nostr.band +wss://nostr.fine +wss://vxlw4rlg7go34ol43g4gxbvfu4txdzjauquvnbptzwjflezs3vik55id.onion +wss://big.fist.black +wss://universe.nostrich.landlangzhlangja +wss://relay.plebz.space +wss://nostrich.land +wss://relay.mynostr.fun +wss://swiss-enigma.ch +wss://nostr1.current.fyi +wss://relay.atlas.nostr.land +wss://nostr.band +wss://n.wingu.se +wss://nostr.jmdtx.com +wss://nostrproxy-1.f7z.io +wss://nostr.ch +wss://roundrockbitcoiners.com +wss://nostr.sept.ml +wss://srelay.roli.social +wss://nostr.monostr.com +wss://nostr.dojotunnel.online +wss://nostrica.dojotunnel.online +wss://nostr.shadownode.org +wss://thes.ai +wss://rsslay.wss +wss://nostr.vol.io +wss://nostrgram.co +wss://habla.news +wss://runningnostr.lol +wss://mostr.pub +wss://relay.example2.com +wss://profiles.f7z.io +wss://nostr.adpo.co +wss://jp-relay-nostr.invr.chat +wss://nostr.anchel.nl +wss://mutinywallet.com +wss://relay.nostrbr.online +wss://filter.eden.nostr.land +wss://relay.nostrdocs.com +wss://relay.nostr.lucentlabs.co +wss://n.xmr.se +wss://nostr.relayer.rs +wss://monad.jb55.com:8080 +wss://nostr.watch +wss://universe.nostrich.landlangenlangzhlangja +wss://nostr.asdf.mx +wss://ts.relays.world +wss://arc1.arcadelabs.co +wss://stealth.wine +wss://nostr.bg +wss://really.nostr.bg +wss://realy.nostr.bg +wss://relai.nostr.bg +wss://relay-verified.deschooling.us +wss://4.up.railway.app +wss://nostr-relay.aapi.me +wss://nostr-z9tc.onrender.com +wss://nostrich.site +wss://nostr.ginuerzh.xyz +wss://310b-200-229-144-129.ngrok.io +wss://nostr.aste.co +wss://black.nostrcity.club +wss://nostr.guru +wss://nostrica.com +wss://relay.leesalminen.com +wss://nostr.shroomslab.net +wss://meta-relay-beta.nostr.wirednet.jp +wss://nostr.reamde.dev +wss://nostr.africa +wss://powrelay.xyz +wss://rsslay.data.haus +wss://nostr.danvergara.com +wss://nostr.one.re +wss://dev2.hazilitt.fiatjaf.com +wss://nostr-2.zebdeee.cloud +wss://zerosequioso.com +wss://brb.io.relay +wss://relay.realsearch.cc +wss://nodestr.fmt.wiz.biz +wss://r.alphaama.com +wss://nostr.relay-wlvs.space +wss://relay.21spiritis.io +wss://nostr.pinkanki.org +wss://nostr.damus.io +wss://fin-nostr.seekdisruption.com +wss://relay.nostr.lu.ke +wss://nostr.rdfried.com +wss://nostr.trustbtc.org +wss://nostr.verymad.net +wss://relay.damus.info +wss://relays.nostrplebs.com +wss://nostr.688.org +wss://15171031.688.org +wss://dgi4mb7antpcmrx4rynm6xq52xzt5duvxa4iwucq4mszgpz6smrjajqd.onion +wss://mastodon.cloud +wss://nostr.ch3n2k.com +wss://nostr.forecastdao.com +wss://nostr.nostrelay.org +wss://nostr.robotesc.ro +wss://nostr.test.aesyc.io +wss://nostr.web3infra.xyz +wss://nostrrelay.maciejz.net +wss://nostrsxz4lbwe-nostr.functions.fnc.fr-par.scw.cloud +wss://nostrpurple.com +wss://rsslay.ch3n2k.com +wss://nos.qghs.in +wss://nostr.nordlysln.net:3241 +wss://nostr.net.in +wss://relay.rip +wss://universe.nostrich.landlangenlangja +wss://wmv-vm.local:4848 +wss://relay.austritch.net +wss://relay.oxtr.dev +wss://rwlay.bigred.social +wss://relay.lexongtonbitcoin.org +wss://knostr.neutrine +wss://nostr.online +wss://filter.stealth.wine +wss://nostream-production-5895.up.railway.app +wss://nostr.stereosteve.com +wss://relay01.apus.network +wss://test.nostr.0x50.tech +wss://nostr.0x50.tech +wss://nostr.256k1.dev +wss://nostr.malin.onl +wss://jqiwgflfw4dezjsy42frompmknrlcfazoiyngftgknj7yrmnhtobd7id.local +wss://b.ayit.org +wss://nostrelay.rajabi.ca +wss://off20chain.pub +wss://nostr.milou.land +wss://nostr.primedomain.fr +wss://nostr.theblockreward.com +wss://anon.computer +wss://relay.hamnet.io +wss://nostramsterdam.vpx.moe +wss://global-relay.cesc.trade +wss://btcpay.kukks.org +wss://relay.cent2sat.com +wss://nostr.mnethome.de +wss://nostream.sh4.red +wss://klockenga.social +wss://nostream.megadope.snowinning.com +wss://nostr.cvilleblockchain.org +wss://nostr.bitocial.xyz +wss://nostr.bitcoiner.socail +wss://nostr-relay.eniehack.net +wss://greenart7c3.dedyn.io +wss://nostr.data.naus +wss://8.tcp.ngrok.io:19607 +wss://relay.nostr24.com +wss://d463rbo7dgbfuxvvxpory2og2etl4gttfzmqcixdq7rpts47lpgolkyd.onion +wss://dublin.saoirse.dev +wss://www.weixin.com +wss://nostr-rs-relay.cryptoassetssubledger.com +wss://nostr.kojira.net +wss://nostr.fan +wss://nostr.pk +wss://getalpy.com +wss://billert.xyz +wss://circle-ay.info +wss://jawsh.xyz +wss://walletofsatoshi.com +wss://ogblock.xyz +wss://nodestrich.com +wss://kunigaku.gith +wss://nostr.21ideas.org +wss://133332.xyz +wss://asats.io +wss://nostrchack.me +wss://chalow.net +wss://cashu.me +wss://tsukemonogit.git +wss://h3y6e.com +wss://elder.nostr.land +wss://xmr.rocks +wss://nostr.build +wss://mofumemo.com +wss://kpherox.dev +wss://sb.nostr.band +wss://tyiu.xyz +wss://welkinhere.githu +wss://ocha.one +wss://in.tips +wss://vitorpamplona.co +wss://fiatjaf.com +wss://akiomik.github.io +wss://stacker.news +wss://nvk.org +wss://lordkno.ws +wss://nostr.indus +wss://lotdkno.ws +wss://nosutora.com +wss://milou.lol +wss://mostr.pu +wss://dergigi.com +wss://shirehodl.com +wss://cash.app +wss://h3z.jp +wss://murachue.cytes.net +wss://snowcait.gith +wss://jb55.com +wss://nodeless.io +wss://orange-crush.com +wss://nostr.com.au +wss://oooxxx.ml +wss://plebs.place +wss://ahr999.com +wss://penpenpng.github.io +wss://nostrpurple.co +wss://thank.eu +wss://weep.jp +wss://tigerville.no +wss://nostrcheck.me +wss://frenstr.com +wss://ln.tips +wss://ryumu.dev +wss://honeyroad.store +wss://harlembitcoin.com +wss://f7z.io +wss://relay.fan +wss://nisshiee.org +wss://www.lopp.net +wss://getalby.com +wss://heguro.com +wss://wil.bio +wss://b.tc +wss://nodedttich.com +wss://relay.taldra.in +wss://relat.nostrica.com +wss://nostr.boring.surf +wss://nostr.raitisoja.net +wss://nostr.astrox.app +wss://nostr.mjex.me +wss://slick.mjex.me +wss://nostr.hrmb.org +wss://relay.semaphore.life +wss://rss.nostr.band +wss://63ragcfwb5xhoe5gfflazfyrde3qjdo73cblhhmnbviizowdo2q5haid.onion:5051 +wss://nostrblip.app +wss://relay.vanderwarker.family +wss://relay-local.cowdle.gg +wss://relay.damus.com +wss://relay.reeve.cn +wss://relay.strfry.net +wss://relay.alxgsv.com +wss://nostrv0l.io +wss://relay.nostrula.com +wss://release.nostr.band +wss://nostr.k3tan.com +wss://nostr.bitcoin.social +wss://thesimplekid.space +wss://relay.ypcloud.com +wss://at.nostrwork.at +wss://nostream.dev.kronkltd.net +wss://nostr-relay.xbytez.io +wss://relay.nostr.io +wss://relay.nvote.co:443 +wss://relay.cryptoculture.com +wss://rjj6ejkihilniytxs56qrgtttgcfnnjvbii6vaas6jzppcmekd63ugad.local +wss://puravida.nostr.land.com +wss://bitcoinmaximalist.online +wss://wine.nostr +wss://nostr.messagepush.io +wss://nostrich.love +wss://relaynostrplebs.com +wss://hamstr.to +wss://yosupp.app +wss://snort.social +wss://relay.nostr.gt +wss://nost.ratchat.nl +wss://nostr.chrissmith.site +wss://i.relay.boats +wss://nostr.wineto +wss://nostr.eluc.ch +wss://nostrplebs.com +wss://nostr.tools.global.id +wss://nostr.rocketnode.space +wss://relay.roli.social +wss://bitcoin.nostr.com +wss://relay.badgr.space +wss://nostriches.club +wss://nostr-check.me +wss://nostrelay.nokotaro.com +wss://rbr.bio +wss://rly.bopln.com +wss://6amyhf3sjvgxe5qzbx4xn52pcnqresdmi7szxurp6umkvz6mthxjdcad.onion +wss://6amyhf3sjvgxe5qzbx4xn52pcnqresdmi7szxurp6umkvz6mthxjdcad.local +wss://20nos.lol +wss://test.theglobalpersian.com +wss://nostr.exposed +wss://nostr-pub.liujiale.me +wss://nostream.frank.snowinning.com +wss://nstrs.fly.dev +wss://eospark.com +wss://relay.nosterplebs.com +wss://nproxy.kristapsk.lv +wss://nostr.universalname.space +wss://relays.snort.social +wss://nostr.how +wss://kukks.org +wss://nostr.dutch.cryptonews +wss://relay.cryptojournaal.net +wss://relay.dutch.cryptonews +wss://nostr.cryptojournaal.net +wss://no-str.wnhefei.cn +wss://www.131.me +wss://rsr.uyky.net +wss://nostr-relay.ie9.org +wss://nostr.fmt.wis.biz +wss://nostr.exotr.dev +wss://nostr.merrcurr.com +wss://realy.damus.io +wss://nerostr.xmr.rocks +wss://rkdgwzgvcgrciemlnfsxqgyrv5whgpw44s6zycokmuchpq4ucflgjtqd.local +wss://nostr.simplex.icu +wss://ralay.damus.io +wss://relay.kronkitd.net +wss://nostr.info +wss://nostr.lnnodeinsight.com +wss://nostr.truckenbucks.com +wss://brt.io +wss://nostr.lingoh.dev +wss://relay.nor.st +wss://nostr-relay.inmarkets.com +wss://wiz.biz +wss://nostream.git +wss://nostr.dpbu.de +wss://wcl2meyp236fa3dmfzfyq6aacbdoixrlocb6zozjs6xklxizschj2did.local +wss://relay.nostr.co.jp +wss://relap.orzv.workers.dev +wss://nostr.bitcoiner.socia +wss://eden.nosrt.land +wss://strfry.cryptocartel.social +wss://nostr.citizenry.technology +wss://universe.nostrich.landlang +wss://nostr.inprivate.network +wss://relay.snort.test +wss://lpkue6jtz3pnp7zok4jwlct4n3mzuffsfrpagiffsuplyaswhdtmpoid.local +wss://nostr.rezhajulio.id +wss://lnbits.eldamar.icu +wss://nostr.freefrom.fi +wss://yael.at +wss://rain8128.github.io +wss://badges.page +wss://latam1-nostr.stealthy.co +wss://nostr.relay.se +wss://nfdn.testnet.dotalgo.io +wss://relav.nostr3.io +wss://ofchain.pub +wss://nostr.fmt.wiz.bi +wss://relay.gui.dog +wss://eden.nostry.land +wss://nostr.relay.limo +wss://relay.nostrichs.org +wss://20nostr.mom +wss://relay20damus.io +wss://nostr.sandwich.pro +wss://sq.qemura.xyz +wss://nostr-pub.seminol.dev +wss://nostr.eunundzwanzig.space +wss://nostr.bitcoinet.social +wss://nostr-relay.untether.me +wss://relay.nostr.pub +wss://nostr.100p.org +wss://7tdom3xuus7ekv423ul46w3j43zyixjj54yoe62bndpcrgii3adeppid.local +wss://nostr.gram +wss://nostr.videre.net +wss://nostr-2.zebedee.cloudwss +wss://nostr-pub.wellorder.netwss +wss://sonzai.net +wss://snort.fail +wss://ppavybjpqjft5slnpeovehbegomhwtvvxtesvwwdrfndz6qe2c5kf2ad.local +wss://nostr.land +wss://relay.nvote.com +wss://purevida.nostr.land +wss://nostr.bitcoiner.soical +wss://nostr.inosta.co +wss://nas.lol +wss://wss.nostr.milou +wss://nostr.cheesebot.org +wss://eyeswideshut.ath.cx +wss://test.relays.world +wss://relay.snort.com +wss://relay.nostrplebs.co +wss://nostr.kimi.im +wss://nostrum.com +wss://wss.nostr.wine +wss://relay.usenostr.org +wss://paladium.my:4848 +wss://umbrel.home.local:4848 +wss://nostr.metamadeenah.com +wss://lnbits.sdbtc.org +wss://relay.nostr.mutinywallet.com +wss://relay.theglobalpersian.com +wss://relay1.easymeta.app +wss://relay.nostris.online +wss://s1.wonder3.org +wss://eden.nostraland +wss://byc.klendazu.com +wss://ephemerelay.mostr.pub +wss://7si6co27cvaw5yjyx6asvxfmaw5ah2arywwgrem4y5svi5ntskoeb5id.onion +wss://nwmdev.com +wss://nostro.online +wss://nostr.massimux.com +wss://nostr.glate.ch +wss://nostr.openordex.org +wss://nostr.schorsch.fans +wss://nostr-relay-dev.nisshiee.org +wss://ibz.me +wss://alexandernostrplebs.com +wss://fishbanananostrplebs.com +wss://relay.nostrcheck.com +wss://nostr.roli.io +wss://nostr.net.za +wss://nostr.worldkey.io +wss://nostr-pub.welloorder.net +wss://nostr.actin.io +wss://nostrzebedee.cloud +wss://nostr.zclub.app +wss://nostr.13x.sh +wss://nostr.totient.xyz +wss://nostr1.federated.computer +wss://nostr.zhix.in +wss://nostr.vdstruis.com +wss://caro-relay.fiatjaf.com +wss://nostr.winewss +wss://notstro.wine +wss://nostr.btc-library.com +wss://nostr.phenomenon.space +wss://nostr.octr.dev +wss://nostr.impervious.live +wss://nostr.plebs.space +wss://iefan.tech +wss://w3ird.tech +wss://yunginter.net +wss://nostr.coach +wss://sleepy.cafe +wss://freespeechextremist.com +wss://nostr.uselessshit.com +wss://liberdon.com +wss://eveningzoo.club +wss://gleasonator.com +wss://mindly.social +wss://ottawa.place +wss://noagendasocial.com +wss://poa.st +wss://misskey.io +wss://misskey.cf +wss://nostr.bybieyang.com +wss://mastodon.online +wss://toad.social +wss://best-friends.chat +wss://universeodon.com +wss://mastodon.world +wss://mastodon.social +wss://nostr.vulpem +wss://nicecrew.digital +wss://front-end.social +wss://nostr-relay.wellorder.net +wss://relays.pro +wss://rsslay.sovbit.host +wss://seal.cafe +wss://social.6bq.de +wss://universe.nostrich.landlangjalangzh +wss://social.xenofem.me +wss://mi.hibi-tsumo.com +wss://mstdn.social +wss://mas.to +wss://relay.rebelbase.site +wss://pixelfed.social +wss://digitalcourage.social +wss://ruby.social +wss://cr8r.gg +wss://nijimiss.moe +wss://returtle.com +wss://lor.sh +wss://toot.community +wss://mstdn.jp +wss://relay.berserker.town +wss://nostr.rajabi.ca +wss://fosstodon.org +wss://misskey.takehi.to +wss://izj3isbk3pmade74ontdijodhehsytnw2iokdhh6k3flk4mq2pau6sid.onion +wss://mastodon.scot +wss://nostriches.org +wss://aus.social +wss://relay.nostr.amane.moe +wss://romancelandia.club +wss://stonez.me +wss://merrcurr.com +wss://nostr.ist +wss://onprem.wtf +wss://fedibird.com +wss://s2.wonder3.org +wss://freespech.casa +wss://disabled.social +wss://relay.house +wss://nostr-pub.welllorder.net +wss://social.teamb.space +wss://infosec.exchange +wss://blockedur.mom +wss://progressivecafe.social +wss://mstdn.ca +wss://c.im +wss://mefi.social +wss://basebitcoinplebs.place +wss://med-mastodon.com +wss://ohai.social +wss://defcon.social +wss://pxlmo.com +wss://zlocur7ctbds4qsdswb3qpkp6n2e2ywqne2fp2tdn4fqubpudfiyxwid.local +wss://thebag.social +wss://mstdn.party +wss://relay.serpae.xyz +wss://clew.lol +wss://qoto.org +wss://relay.exchange +wss://nostr.relayable.org +wss://mastodon.coffee +wss://kmy.blue +wss://home.social +wss://detmi.social +wss://brighteon.social +wss://nostr.nom +wss://theblower.au +wss://astral.nostr.land +wss://beige.party +wss://orangepill.dev +wss://redgreenblue.click +wss://nostr.fredix.xyz +wss://nostr.essydns.ca +wss://nostr.private.network +wss://nostr.member.cas +wss://nostr-rely.digitalmob.ro +wss://relay.nostr +wss://relay.current +wss://no-str.or +wss://pl.gamers.exposed +wss://studentchadpolytechnic.com +wss://scicomm.xyz +wss://relay.alien-sos.gov +wss://masto.es +wss://spinster.xyz +wss://parallels-parallels-virtual-platform.local:4848 +wss://relay.daums.io +wss://kolektiva.social +wss://mastodonapp.uk +wss://convo.casa +wss://sfba.social +wss://techhub.social +wss://leafposter.club +wss://nrw.social +wss://mastodon.uno +wss://handon.club +wss://social.vivaldi.net +wss://nostr.goller.net +wss://minazukey.uk +wss://mstdn.beer +wss://expressional.social +wss://paid.nostr.0x50.tech +wss://mstdn.nere9.help +wss://relay.nostr.ai +wss://relay.noswss +wss://relay.nwss +wss://furry.engineer +wss://uselessshit.co +wss://kosmos.social +wss://mynostr.io +wss://premis.one +wss://social.tchncs.de +wss://retro.pizza +wss://pearl-mount-showed-fishing.trycloudflare.com +wss://kpa4k6acxzjv2m2p72keftbpaymwpq2h67jqnin3d4y3djxyheuifoqd.onion +wss://gm7.social +wss://relays.nostr.info +wss://chitter.xyz +wss://hackers.town +wss://anarchism.space +wss://relay.nostrica +wss://halifaxsocial.ca +wss://asimon.org +wss://nostr.blipme.add +wss://troet.cafe +wss://octodon.social +wss://m.cmx.im +wss://filename-ambassador-distance-mountains.trycloudflare.com +wss://nostr.getgle.org +wss://relay.froth.zone +wss://novoa.nagoya +wss://relay.dispute.systems +wss://clubcyberia.co +wss://thechimp.zone +wss://coolsite.win +wss://puravida.nostra.land +wss://shelter.local:1111 +wss://det.social +wss://nostr-2.zebee.cloud +wss://chaosfem.tw +wss://nostr.v01.io +wss://social.kechpaja.com +wss://mastodon.green +wss://plebchain.nostr +wss://plebchain.nostr.land +wss://relay.onsats.org +wss://u5epuanp2fbie4phw6zekzna6zotvsffji4td4ee7iwgwdxlz4kwqqad.onion:5051 +wss://3ddc8bbee6db.ngrok.app +wss://b4968f09859e.ngrok.io +wss://genserver.social +wss://masto.ai +wss://hachyderm.io +wss://shitpost.cloud +wss://oldbytes.space +wss://mastodon.ie +wss://baraag.net +wss://nostr.dvdt.dev +wss://relay.com.de +wss://nostr.rbel.co +wss://bologna.one +wss://nostr-relay.app +wss://kagamisskey.com +wss://nostr-rs-relay.phamthanh.me +wss://nostr.bcmp.com +wss://blogstack.io +wss://rly.nostrkid.com +wss://mastodon.bida.im +wss://freeatlantis.com +wss://pieville.net +wss://climatejustice.rocks +wss://relay.mynostr.id +wss://relay.farscapian +wss://relay.blogstack.io +wss://orwell.fun +wss://misskey.04.si +wss://sushi.ski +wss://nostr.milou.lo +wss://pawoo.net +wss://tooter.social +wss://mastodon.sdf.org +wss://nostr.com +wss://misskey.design +wss://macaw.social +wss://relay.nostr.inforelay.nostr.band +wss://pub1.southflorida.ninja +wss://strawberry-pudding.net +wss://mastodon-japan.net +wss://nostream.0x50.tech +wss://multiplextr.coracle.social +wss://pleroma.skyshanty.xyz +wss://uxxq6b2enojvflhkrzsg4erakd5rrb7v2cql4m4pspj4xtqwyli47rid.local +wss://masto.deoan.org +wss://replay.damus.io +wss://melhorque.com.br +wss://nostr1.actn.io +wss://nostr.bolt.fun +wss://relay.vtbmoyu.com +wss://eosla.comrelay.zeh.app +wss://bikeshed.party +wss://nostr.xanny.family +wss://milker.cafe +wss://nostr.give.africa +wss://relay.got-relayed.com +wss://cum.salon +wss://puravid.nostr.land +wss://soc.punktrash.club +wss://seafoam.space +wss://h4.io +wss://nostr.swiss.enigma.ch +wss://toot.cafe +wss://sneed.social +wss://newsie.social +wss://indg.club +wss://xoxo.zone +wss://relay.nostr.bitcoiner.social +wss://relay.snort.band +wss://socel.net +wss://social.coop +wss://postpandemicparty.org +wss://merveilles.town +wss://search.nostr.wine +wss://search.nos.today +wss://mstdn-huahin.com +wss://eden.nostr.la +wss://nostrja-kari-nip50.heguro.com +wss://relay.gems.xyz +wss://plnetwork.xyz +wss://nostr.swiss-enigma.sh +wss://geofront.rocks +wss://toot.io +wss://indieweb.social +wss://mastodon.content.town +wss://awaymessage.club +wss://relay.intify.io +wss://mstdn.science +wss://maniakey.com +wss://otadon.com +wss://mstdn.guru +wss://misskey.noellabo.jp +wss://hessen.social +wss://mastodon.top +wss://ipv6.nostr.wirednet.jp +wss://relay.nostr-relay.org +wss://cum.camp +wss://nebbia.fail +wss://current.fyi +wss://bae.st +wss://lolison.network +wss://ioc.exchange +wss://bylines.social +wss://decayable.ink +wss://nostr.unitedserializer.com +wss://urbanists.social +wss://dark-elves.social +wss://writing.exchange +wss://nostr.rikmeijer.nl +wss://misskey.social +wss://ht.nixre.net +wss://mathstodon.xyz +wss://t7jvqwu35hneszx7fihsprbcpwonlcfnsjr4xtn6shqgwbv324w4gdid.local +wss://abla.news +wss://muenchen.social +wss://homeserver.drake-carp.ts.net:4848 +wss://snailedit.social +wss://mastodon.gamedev.place +wss://tech.lgbt +wss://mast.lat +wss://econtwitter.net +wss://veganism.social +wss://btclolap6mm4tl37huslk6j76enq7qxaj2kwq7w6cdr5ros56eletcqd.onion +wss://toot.cat +wss://nostr.zenon.info +wss://misskey.art +wss://nostr.hushvault.ie:4848 +wss://o6ga6lxnax2z7pgkkenifollohkrv55r36mdzdtofi7d5yyif2f4o5yd.onion:5051 +wss://20nostr-pub.wellorder.net +wss://ecoevo.social +wss://nostr.zerofiat.world +wss://nostr.atitlan.io +wss://detroitriotcity.com +wss://rollenspiel.social +wss://paquita.masto.host +wss://literatur.social +wss://dave.st.germa.in +wss://sunny.garden +wss://nostrpro.xyz +wss://relay.getalby.com +wss://misskey.systems +wss://mamot.fr +wss://social.anoxinon.de +wss://relay.nostr.social +wss://mindmachine.org +wss://microblog.club +wss://relay.utxo.com +wss://universe.nostrich.landlangth +wss://social.teci.world +wss://social.freetalklive.com +wss://mk.absturztau.be +wss://social.ornella.xyz +wss://left-tusk.com +wss://bofh.social +wss://a11y.social +wss://shroomslab.net +wss://relay2.nostr.vet +wss://mugicha.club +wss://laserbeak.local:4848 +wss://annihilation.social +wss://humble.cafe +wss://nostr.relay.damus.io +wss://nostr.milol.lol +wss://nostr.blimpme.app +wss://noc.social +wss://wetdry.world +wss://nostr.taxi +wss://nostr.21-bitcoin.org +wss://relay.llevotu-bitcoiners.info +wss://pl.kitsunemimi.club +wss://djsumdog.com +wss://citadel.local:4848 +wss://federate.blogpocket.com +wss://chaos.social +wss://mastodon.me.uk +wss://oxtr.dev +wss://misskey.cloud +wss://varishangout.net +wss://lacosanostr.com +wss://willem.currycash.net:4848 +wss://lightniningrelay.com +wss://queer.party +wss://lightning.relay.com +wss://mastodon.nl +wss://purplepag.es +wss://cupoftea.social +wss://bitcoiner.socialwss +wss://relay.current.io +wss://sigmoid.social +wss://wandering.shop +wss://braydmedia.de +wss://quey.la +wss://nostr.zebeedee.cloud +wss://nostr-2.zebeedee.cloud +wss://artsio.com +wss://nostr1676031941328.app.runonflux.io +wss://arsip.ddns.net +wss://relay.nostrcitadel.org +wss://relay.nostr-citadel.org +wss://nostr-citadel.org +wss://blastr.f7z.io +wss://nostr.myowndamnnode.com +wss://snowdin.town +wss://nostr.zxcvbn.space +wss://relay.notmandatory.org +wss://bitcoin.social +wss://friendsofdesoto.social +wss://zirk.us +wss://digipres.club +wss://nostr-test.elastos.io +wss://nostr.onsat.org +wss://damus.relay.io +wss://beefyboys.win +wss://nostrija-kari.heguro.com +wss://froth.zone +wss://ns.penseer.com +wss://relay.nostrical.com +wss://nostr.hoshizora.ch +wss://kunigaku.github.io +wss://nostr.shino3.net +wss://umbrel.tailbb128.ts.net:4848 +wss://tailbb128.ts.net:4848 +wss://fedi.twoshortplanks.com +wss://filter.nostr.winebroadcasttrue +wss://nostr.doufu-tech.com +wss://relay.hodl.haus +wss://pgh.social +wss://coeditor-congested.fractalnetworks.co +wss://mastodon.podaboutli.st +wss://frenfiverse.net +wss://nostr.f4255529.fun +wss://nostream.megadope.snowinning +wss://kiritan.work +wss://forever21.lol +wss://zitron.net +wss://mastodon-swiss.org +wss://relay1.current.fyi +wss://nostr.plebs.com +wss://multiplextr.corocal.social +wss://nostr.zedebee.cloud +wss://nostr.mutinywallet.comisntbanned.addthatonesotheycangetnotesrelayedtotherestofthenetworkfrominsideofchina +wss://mastodon.mit.edu +wss://relaynostrati.com +wss://relaynostr.band +wss://relaynostr.info +wss://relaychenxixian.cn +wss://relaysnort.social +wss://relaynostr.com.au +wss://nostr-tbd.website +wss://relay.hoshizora.ch +wss://social.balsillie.net +wss://strangeobject.space +wss://relay.nvote20.co +wss://fla.red +wss://urusai.social +wss://chad.polytechnic.com +wss://robo358.com +wss://conxole.io +wss://relay.ohbe.me +wss://nostr.bitcoiner.com +wss://www.mutinywallet.com +wss://x.9600.link:10070 +wss://a11y.info +wss://homelab.host +wss://k65qz57zx4sw24fow2bvchjgmpjqljj4cp3oa7dtpbbprjifsdotggid.local +wss://relay.vtuber.directory +wss://x.9600.link:8000 +wss://nostr.plebs.win +wss://renkontu.com +wss://nost.massmux.com +wss://submarin.online +wss://social.librem.one +wss://relai.kongerik.et +wss://mstdn.io +wss://astral.swiss-enigma.ch +wss://stereophonic.space +wss://relayer.pleb.social +wss://mastodon.nz +wss://nostr.nostr.de +wss://nostr.thezap.club +wss://proxy.shroomslab.net +wss://pfr24mrpxowclhm4y6adu36kbo3erx7gskzyfqqhnhfpdkdmylpfgkyd.local +wss://nostr.hodl.haus +wss://vtdon.com +wss://relay.nost.band +wss://fnxwipsg3lfzij64lvjgmutvkkpd7eo2mr2khxkofyywf3vsvbk73jad.onion +wss://fnxwipsg3lfzij64lvjgmutvkkpd7eo2mr2khxkofyywf3vsvbk73jad.local +wss://md.hugo.nostr +wss://boks.moe +wss://truthsocial.co.in +wss://mastodon.xyz +wss://relay.universalname.space +wss://relay-nostr.wirednet.jp +wss://fedi.pawlicker.com +wss://favcalc.com +wss://rot13maxi.com +wss://awayuki.net +wss://mazinkhoury.com +wss://g0v.social +wss://shpposter.club +wss://a.lufimianet.jp +wss://pura20vida.nostr.land +wss://sotalive.net +wss://sendsats.lol +wss://vida.page +wss://wagvwfrdrikrqzp7h3b5lwl6btyuttu7mqpeji35ljzq36ovzgjhsfqd.onion +wss://uec2cmjauzufrtlq6wq6l2ujfncdvo3suezz423gsvz5xvhehm2mcgid.onion +wss://mastodon-belgium.be +wss://rejecttheframe.xyz +wss://nogood.store +wss://getaiby.com +wss://plebchain.club +wss://nostrverified.com +wss://x.9600.link +wss://n0p0.shroomslab.net +wss://orangemakura.xyz +wss://jamw.net +wss://7ab7qqbj2dw3pjnkoskgsfn4ikqc7orwnkpmcfjmeobw63kf4zgykjid.local +wss://snabelen.no +wss://floss.social +wss://mastoot.fr +wss://kmc-nostr.amiunderwater.com +wss://hodl.camp +wss://xmr.usenostr.com +wss://nostr-pub.wellorn.net +wss://gudako.net +wss://ryona.agency +wss://kafeneio.social +wss://massmux.com +wss://freezepeach.online +wss://nostream-production-f83d.up.railway.app +wss://taobox.pub +wss://mastodon.radio +wss://einundzwanzig.relay.com +wss://journa.host +wss://social.here.blue +wss://toot.wales +wss://staging.nostr.com.se +wss://pleroma.soykaf.com +wss://berserker.town +wss://zapforart.site +wss://forall.social +wss://nostrja-kari.heguro.comyee +wss://higheredweb.social +wss://social.gnuhacker.org +wss://the.hodl.haus +wss://ng4jk6yiqgfczo4wyxszuj7w6jok3fptehu533o3mlzs3vph3dvjfdid.onion +wss://nostr.mtpx.ovh +wss://relay.coollamer.com +wss://glasgow.social +wss://fedi.absturztau.be +wss://nostr.frostr.xyz +wss://relay.runningnostr.lol +wss://relay2.vtuber.directory +wss://nerdculture.de +wss://nostr-relay.untethr.meoperator +wss://nostr.verif-slothy.win +wss://nostr.pub +wss://social.process-one.net +wss://invillage-outvillage.com +wss://otofu.uk +wss://universe.nostrich.landlangenlangpt +wss://mastodon.iriseden.eu +wss://frighteningdeafeningagent.nailuogg.repl.co +wss://obo.sh +wss://relay.hodlhaus.net +wss://rdrama.cc +wss://nostr.packetlostandfound.us +wss://test.relay +wss://mastodonbooks.net +wss://southflorida.ninja +wss://blob.cat +wss://tooting.ch +wss://relay.pineapple.pizza +wss://relay.nostr.directory +wss://relar.nostr.bg +wss://reisen.church +wss://relay.honk.pub +wss://nostr.rsfriedl.com +wss://relay.nort.social +wss://1611.social +wss://the.hodl.house +wss://relayable.com +wss://fedi.syspxl.xyz +wss://nostrpub.yeghro.site +wss://skr5bbrgzfnideglw4cs2iw6au2jm2b7gupocxbmkv5qopo6rcitmiqd.local +wss://a2mi.social +wss://status.relayable.org +wss://toot.blue +wss://btcqspp5dl4rlgl5pomcyv3odfeki7a5zrmjoekyu5vsoqz5bth4e7yd.onion +wss://bitcoinr6de5lkvx4tpwdmzrdfdpla5sya2afwpcabjup2xpi5dulbad.onion +wss://7tdom3xuus7ekv423ul46w3j43zyixjj54yoe62bndpcrgii3adeppid.onion +wss://dnze4ekho2kuiejwatjw5omeprtmdaum2ukok52roiu5rztii3rp2aid.onion +wss://53snncs7vegargpaardbxjnii2oan3xpmbeaf6czwoqa2axz5mvbsjid.onion +wss://fnqdhz3df33da6wxg7jskvumd5rjn3nknln6ecun7uwwysc7vkwkjgid.onion +wss://relay.thefockinfury.wtf +wss://silliness.observer +wss://freak.university +wss://piaille.fr +wss://nostr.weking.tk +wss://f.reun.de +wss://radixrat.com +wss://hostux.social +wss://chat.freenode.net +wss://no.str..cr +wss://nostr.inoata.cc +wss://kappa.seijin.jp +wss://floyds.io +wss://mast.dragon-fly.club +wss://zbd.ai +wss://misc.name +wss://pdx.social +wss://0w0.is +wss://d6jvu2tev2rblkuzgu4ydw2413jizr53j26ut47hxpykvtusbvekhiid.onion +wss://d6jvu2tcv2rblkuzgu4ydw24l3jizr53j26ut47hxpykvtusbvekhiid.onion +wss://drcassone.social +wss://mastodon.energy +wss://rayci.st +wss://ischool.social +wss://nostr.halfway2forever.com +wss://relay.nostr.rocks +wss://nostr.stoner.com +wss://2nodez.com +wss://rs.nostr-x.com +wss://schleuss.online +wss://thrashzone.org +wss://relay.nostrgraph.com +wss://relay.2nodez.com +wss://occult-zuki.com +wss://mastodon.lithium03.info +wss://bigbadpc.local:4848 +wss://social.gr0k.net +wss://nostr.wirednet.jp +wss://relay.plebster.com +wss://bitcoin.nostr +wss://mastodon.im +wss://brb..io +wss://nostr.sandwhich.farm +wss://relay.nos.lol +wss://beta.nostr.v0l.io +wss://eden.nostr.space +wss://powerlay.xyz +wss://rap.social +wss://relay.mutinywallet.com +wss://rogue.earth +wss://600.wtf +wss://klabo.blog +wss://petrikajander.com +wss://tgkzmdd.help +wss://nostr.red +wss://brb.lol +wss://jz2l2bf6f6wssdqwkg7ogthkc5i3ymyiwkaz3tbhff6ro3h3zqddekyd.onion +wss://mstdn.mini4wd-engineer.com +wss://nostr.exposd +wss://nostr.a-ef.org +wss://computerfairi.es +wss://social.targaryen.house +wss://o3o.ca +wss://walkah.social +wss://cosocial.ca +wss://filter.nostr.band +wss://relais.nostrview.com +wss://gigaohm.bio +wss://dobbs.town +wss://bark.lgbt +wss://mastodon.gal +wss://snug.moe +wss://genomic.social +wss://relay.orangepilldev.com +wss://social.sdf.org +wss://social.camph.net +wss://mstdn.poyo.me +wss://nein.lol +wss://nostr.i00.org +wss://kemono.ink +wss://mu.zaitcev.nu +wss://libera.site +wss://ca.hibi-tsumo.com +wss://social.bund.de +wss://xscape.top +wss://social.lol +wss://birds.town +wss://arnostr.com +wss://nostr.33co.de +wss://relay.nostr.lighting +wss://metadata-contacts-relays.pages.dev +wss://webs.node9.org +wss://pleroma.elementality.org +wss://suya.place +wss://livellosegreto.it +wss://peoplemaking.games +wss://nattois.life +wss://typo.social +wss://neutrine.com +wss://ragner-relay.com +wss://wss.nostr.uselessshit.co +wss://wss.nostrue.com +wss://relay.nvote.co:433 +wss://disobey.net +wss://rneetup.com +wss://arnostr.com:8433 +wss://relay.uxto.one +wss://relay.hackerman.pro +wss://thisis.mylegendary.quest +wss://poliversity.it +wss://sats.lnaddy.com +wss://rs2.abaiba.top +wss://rs1.abaiba.top +wss://rs2.abaiba.top.abaiba.top +wss://social.matarillo.com +wss://nostr01.counterclockwise.io +wss://backup.local:4848 +wss://touhou.vodka +wss://mi-wo.site +wss://nostr.f7z.io +wss://alive.bar +wss://strfry.nostr-x.com +wss://mastodontti.fi +wss://nostr.wellorder.net +wss://y.9600.link:8000 +wss://ephemrelay.mostr.pub +wss://byc-italia.online +wss://fissionator.com +wss://stranger.social +wss://eupolicy.social +wss://nostr-desktop.local:4848 +wss://aoir.social +wss://mstdn.plus +wss://nostrproxy.io:3333 +wss://mastodon.hams.social +wss://jorts.horse +wss://metalhead.club +wss://dice.camp +wss://mstdn.y-zu.org +wss://loffchain.pub +wss://mastodon.llarian.net +wss://nostr-relay2.thefockinfury.wtf +wss://2g2jzcfgq5lcrceuq23lmya2drm3ku5qmqimr3bvu3amol55vidctrad.onion +wss://mastodon.au +wss://bgme.me +wss://nostr.badran.xyz +wss://nostr.coincreek.com +wss://nostream-test.up.railway.app +wss://relay.blackthunder.click +wss://relay.grorp.com +wss://atomicpoet.org +wss://iddqd.social +wss://gusto.masto.host +wss://lifehack.social +wss://blorbo.social +wss://freecumextremist.com +wss://13bells.com +wss://rsslay.nostr.netrelay +wss://relay.zerosequioso.com +wss://nauka-relay.herokuapp.com +wss://nostr.nofdeofsven.com +wss://out.of.milk +wss://cawfee.club +wss://r.relay.fan +wss://alo.ottonove891.cf +wss://keinoha.tailnet-0240.ts.net +wss://nostr.paralelnipolis.cz +wss://tuiter.rocks +wss://elizur.me +wss://nostr-dev.newstr.io +wss://discuss.systems +wss://blahaj.zone +wss://mastodon.art +wss://makersocial.online +wss://gamepad.club +wss://nostr.flameofsoul.ru +wss://dmv.community +wss://relay.nostr.com +wss://nostr-desktop.saiga-shark.ts.net:4848 +wss://nostrfoxden.ddns.net:4848 +wss://soc.umrath.net +wss://ravenation.club +wss://oisaur.com +wss://nostr-relay.net +wss://social.mikutter.hachune.net +wss://lewacki.space +wss://fediscience.org +wss://todon.eu +wss://nuccy-nuc7i5bnk.local:4848 +wss://games.gamertron.net:4848 +wss://fiedlerfamily.net +wss://postnstuffds.lol +wss://nostr.planetary.social +wss://worldkey.io +wss://hcommons.social +wss://gymp7qquljs47xbbvs47hkptnyyzegy2jkst26mkjxaciifqffjatqid.onion +wss://rs3.abaiba.top +wss://sudo-nostr.com +wss://satgag.site +wss://nostr.lnbitcoin.cz +wss://relay20nostrplebs.com +wss://2pbkpndvpeebljfvjew6auq63lndzszqnntct5aqfmazslerzxe75kad.onion +wss://dragonchat.org +wss://welcome.nostr.wine +wss://relay.nostr.land +wss://social.linux.pizza +wss://dnppj4kopczovvzvpzmihv2iwe5wt3gbrxjnltjc2zdjpttrdz4owpad.onion +wss://potofu.me +wss://nostrbr.online +wss://mastorol.es +wss://notebook.taild34d0.ts.net +wss://t.aqn.jp +wss://nostr.mutinywallet +wss://wcone.nostr.wine +wss://norden.social +wss://eostagram.com +wss://shigusegubu.club +wss://toot.jkiviluoto.fi +wss://kiwifarms.cc +wss://swiss-talk.net +wss://v532btfg2fb4za2g476a7w23pgpkllc7uq274wqtktwjogt5ynb3ukqd.local +wss://mstdn.maud.io +wss://arc1.arcadelabs.com +wss://nostr.jp +wss://relay-jp.nostr.wirrdnet.jp +wss://climatejustice.social +wss://witter.cz +wss://mastodon.pnpde.social +wss://ttrpg-hangout.social +wss://beehaw.org +wss://thecanadian.social +wss://nostr.fbxl.net +wss://relay.sandwich.farm +wss://nostr.olwe.link +wss://botsin.space +wss://zeroes.ca +wss://photog.social +wss://paid.nostr.lc +wss://free.nostr.lc +wss://test.nostr.lc +wss://gzanlkgurj7zd3psqms3da4vrw4imurnyyzaycfuiiug7elqow7xlayd.onion:5051 +wss://masto.nu +wss://mastodon.uy +wss://bit.relay.center +wss://offchain.relay.center +wss://damus.relay.center +wss://wine.relay.center +wss://eden.relay.center +wss://moth.social +wss://nostr.masmux.com +wss://chrome.pl +wss://mastodon.ktachibana.party +wss://ak.kawen.space +wss://mementomori.social +wss://relay.s3x.social +wss://lnbits.michaelantonfischer.com +wss://yof23ggqmert72c5wcl5qglphapy3o2xjdedtkbrn2dt5rbae2s7f6qd.onion +wss://relay.snort.socail +wss://post.lurk.org +wss://yiff.life +wss://q3zaylwjjhq77yzx34lbydz26szzjljberwetkjgxgsapcekrpjzsmqd.onion +wss://lnbits.b1tco1n.org +wss://welcome.nostr.relay +wss://sound-money-relay.denizenid.com +wss://carnivore-diet-relay.denizenid.com +wss://africa.nostr.joburg +wss://nostr.jolt.run +wss://nostr.chainbits.co.uk +wss://ithurtswhenip.ee +wss://nostr.cloudversia.com +wss://relay1.east.us.nostr.btron.io +wss://ca.orangepill.dev +wss://pdx.land +wss://linh.social +wss://okla.social +wss://androiddev.social +wss://spore.social +wss://mastodo.fi +wss://kabedon.space +wss://nost.inosta.cc +wss://relay2cdamus.io +wss://nostr.openhoofd.nl +wss://dragonscave.space +wss://genart.social +wss://dewp.space +wss://layer8.space +wss://qou7zzll2mxx2ehl73n6pptmhizl5b3entowljlin3sqhcvltxdtlmad.onion:5051 +wss://nostr.wines +wss://relay.snort.relay.ryzizub.com +wss://pixelfed.de +wss://nostr.holyscapegoat.com +wss://nostr.einunzwanzig.space +wss://nostr.hifish.org +wss://colearn.social +wss://topspicy.social +wss://mastodon.neat.computer +wss://relay.nostr.hach.re +wss://nostr.dakukitsune.ca +wss://7ab7qqbj2dw3pjnkoskgsfn4ikqc7orwnkpmcfjmeobw63kf4zgykjid.onion +wss://esq.social +wss://famichiki.jp +wss://tribe.net +wss://masto.nobigtech.es +wss://umbrel-nuc.local:4848 +wss://mastodon.cocoasamurai.social +wss://debian.taildd32b.ts.net:4848 +wss://vlt.ge +wss://relay.johnnyasantos.com +wss://snort.relay.center +wss://nb.relay.center +wss://waag.social +wss://concentrical.com +wss://stat.rocks +wss://oransns.com +wss://relay-jpp.nostr.wirednet.jp +wss://oc.todon.fr +wss://jundow.gitlab.io +wss://neurodifferent.me +wss://jazztodon.com +wss://nostrich.friendship +wss://indieauthors.social +wss://werunbtc.com +wss://frogtalk.lol +wss://pop-os.local:4848 +wss://fediver.de +wss://d6qxo55dhms6revgrmbindvb5ejd3gw5hrji7ylkm6khghii3hjs3uyd.onion +wss://eldritch.cafe +wss://karlsruhe-social.de +wss://social.yl.ms +wss://nostr.mycloudhouse.duckdns.org +wss://nostr.otc.sh +wss://nya.social +wss://relay2.nostrchat.io +wss://relay1.nostrchat.io +wss://nostrja-world-relays-test.heguro.com +wss://ndk-relay.local +wss://reespeech.casa +wss://pleroma.atyh.cc +wss://lawfedi.blue +wss://akkoma.jasminetea.uk +wss://peeledoffmy.skin +wss://plush.city +wss://astrodon.social +wss://samenet.social +wss://toot.bike +wss://mi.yukioke.com +wss://social.growyourown.services +wss://mastodon.nu +wss://lou.lt +wss://functional.cafe +wss://relaydamus.io +wss://coma.social +wss://social.fbxl.net +wss://biplus.social +wss://toots.matapacos.dog +wss://psychoet.ml:3250 +wss://danserver.equipment +wss://nostr.lacrypta.com.ar +wss://wonkodon.com +wss://nostr.seankibler.com +wss://autistics.life +wss://cambrian.social +wss://rvqkqr5kl3dvvxyn67rfowcnvoflx4zby5tjbysavym4ycckti4dbjyd.onion +wss://swiss.nostr.lc +wss://snac.saifulh.online +wss://loma.ml +wss://nostr.privoxy.io +wss://366.koyomi.online +wss://mastodon.stormy178.com +wss://podcastindex.social +wss://bitcoiner.socia +wss://fedi.ml +wss://replayable.org +wss://nostr.schroomslab.net +wss://nostr.global.fans +wss://relay.weedstr.net +wss://vocalodon.net +wss://relay.nostr.bandadd +wss://nostr.oxtr.devadd +wss://jarvis.taild68e2.ts.net:4848 +wss://t7jvqwu35hneszx7fihsprbcpwonlcfnsjr4xtn6shqgwbv324w4gdid.onion +wss://stonez.local:4848 +wss://notrustverify.ch +wss://woof.group +wss://mastodon.floe.earth +wss://lnbits.plebtag.com +wss://kpop.social +wss://relay.wavlake.com +wss://mastodon.sharma.io +wss://travelpandas.fr +wss://alphapanda.prowss +wss://relay.saes.io +wss://barelysocial.org +wss://masto.komintern.work +wss://norcal.social +wss://nostr.zbd.gg +wss://mk.outv.im +wss://mstdn.mx +wss://col.social +wss://nostr.freedom.fi +wss://filter.nostr.winebroadcasttrueglobalall +wss://eden.nostr.landv +wss://me.dm +wss://emacs.ch +wss://winonostr.wine +wss://infoplebstr.com +wss://mas.towss +wss://gruene.social +wss://relay.freeplace.nl +wss://itis.to +wss://bsky.social +wss://lnbits.thefockinfury.wtf +wss://5xxkt7zvmh4zdsjw64lgvchjdlrrgw4w2huujiiud35qms6gnkn5azad.onion +wss://eientei.org +wss://artisan.chat +wss://nustr.mom +wss://relay.nostrhraph.net +wss://shitposter.club +wss://nostril.cam +wss://nostr.spaceshell.xyz +wss://relay.wtr.app +wss://tdd.social +wss://d3meec25b53kegrnjmtmtyynikbkmuxf4jqgtk3sonjs6e62hpaezyqd.onion +wss://tkz.one +wss://freerelay.xyz +wss://nfdn.betanet.dotalgo.io +wss://mitra.social +wss://hablanews.io +wss://calle.wtf +wss://voskey.icalo.net +wss://nostr.sloyhy.win +wss://framapiaf.org +wss://nostrnodeofsven.com +wss://ciberlandia.pt +wss://gnusocial.net +wss://relay.s3x.socia +wss://paste.2nodez.com +wss://union.place +wss://bofh.socia +wss://sovbit.dev +wss://lnbits.btc-payserver.eu +wss://osna.social +wss://im-in.space +wss://junxingwang.org +wss://relay.nostr.wirednet.jpcheck +wss://libranet.de +wss://fedisnap.com +wss://woodpecker.social +wss://gensokyo.town +wss://social.imirhil.fr +wss://links.potsda.mn +wss://law-and-politics.online +wss://nostrich.bar +wss://tweesecake.social +wss://nostr.kisiel.net.pl +wss://relay.kisiel.net.pl +wss://calckey.social +wss://nostr.cercatrowa.me +wss://meganekeesu.tokyo +wss://lndiscs.duckdns.org +wss://omochi.xyz +wss://wue.social +wss://nostr.libreleaf.com +wss://rusnak.io +wss://rsslay-production.up.railway.app +wss://nostr.yuhr.org +wss://bod4ojj37fneith2setv3qjbii563wesbjqgdipdz4ag6voic2xk5iad.onion +wss://fediverse.blog +wss://pouet.chapril.org +wss://baq5ufl2rnczpalnoqabxwpjm3kvhzduwgvptxzx7yq37oqdbgf65syd.local +wss://baq5ufl2rnczpalnoqabxwpjm3kvhzduwgvptxzx7yq37oqdbgf65syd.onion +wss://cryptodon.lol +wss://nostr.debancariser.com +wss://mizunashi.hostdon.ne.jp +wss://relay.deezy.io +wss://bbq.snoot.com +wss://historians.social +wss://mi.mashiro.site +wss://mastodonpost.social +wss://nostrpub.welliorder.net +wss://social.cologne +wss://metapixl.com +wss://wandzeitung.xyz +wss://lightninhrelay.com +wss://techopolis.social +wss://lnbits.btcpins.com +wss://purplenostrich.com +wss://onewilshire.la +wss://sself.co +wss://anygemini13.blogs.sapo.pt +wss://federated.press +wss://metadata.nostr.com +wss://nostr.hodl.ar +wss://goreslut.xyz +wss://mastodon.com.tr +wss://climatejustice.global +wss://brotka.st +wss://sueden.social +wss://mstdn.fr +wss://abid.cc +wss://lnbits.fuckedbitcoin.com +wss://meow.social +wss://nostr.rehab +wss://mstdn.media +wss://nodeo1.nostress.cc +wss://nostrmassmux.com +wss://sauropods.win +wss://civilians.social +wss://pnw.zone +wss://zebeedee.cloud +wss://nostr.walletofsatishi.com +wss://aufovmqaxj5nhqmtorhgpogdjxefhkff25cbyyjt2sub3vwg6b6rplid.onion +wss://forfuture.social +wss://76f67qcwxsxpz7cfozlzunota2ejqznpldc5pnqtyq233hjpjzrmlfid.local +wss://toot.garden +wss://umbrel.tail9dfb.ts.net:4848 +wss://mastodon.chasem.dev +wss://misskey.pm +wss://merovingian.club +wss://chirp.enworld.org +wss://paid.no.str.ce +wss://masto.bike +wss://masto.1146.nohost.me +wss://eosla.comno-str.orgrelay.zeh.appno-str.orgrelay.zeh.app +wss://nixnet.social +wss://pay.zapit.live +wss://respublicae.eu +wss://nekomiya.net +wss://mastodon.internet-czas-dzialac.pl +wss://plushies.social +wss://lnb.openchain.fr +wss://mastodon.lol +wss://social.rebellion.global +wss://ruhr.social +wss://mi.farland.world +wss://pkutalk.com +wss://systemli.social +wss://nostr.minimue81.selfhost.com +wss://mastodon.la +wss://everything.happens.horse +wss://pagan.plus +wss://clacks.link +wss://u-tokyo.social +wss://fediverse.projectftm.com +wss://mastodon.bachgau.social +wss://social.kabi.tk +wss://ty3zdjkwlxo4zah6tgdoolznjcbvkhxpcvjyqe2buxeg23hbeyvr3rad.local +wss://pleroma.wakuwakup.net +wss://social.horrorhub.club +wss://nostr.nightowlstudios.ca +wss://mastodon.ml +wss://relay.orangepillapp.com +wss://misskey.sup39.dev +wss://mfmf.club +wss://pokemon.mastportal.info +wss://gohan-oisii.net +wss://aipi.social +wss://nostr.semisol.com +wss://oslo.town +wss://relay.layer.systems +wss://naharia.net +wss://social.elbespace.de +wss://linuxrocks.online +wss://b81m3pf94ridtry53g8ufyyrjtjaoxgbyjbs5k8qrqkr1whocxiy.loki:8080 +wss://lvl01.tater.ninja +wss://kinky.business +wss://relay.bitblockboom.com +wss://fedi.omada.cafe +wss://social.secret-wg.org +wss://celebrity.social +wss://weirdo.network +wss://mastodon.design +wss://berlin.social +wss://misskey.yukineko.me +wss://mindmachine.688.org +wss://sackheads.social +wss://a.farook.org +wss://social.ridetrans.it +wss://nostr-2.crypticthreadz.com +wss://test.itas.li +wss://fashionsocial.host +wss://ordinary.cafe +wss://social.arinbasu.online +wss://nostr.crypticthreadz.com +wss://relay.zebedee.cloud +wss://nostr.pub.wellorder.net +wss://09d4-5-161-189-144.ngrok-free.app +wss://andalucia.social +wss://udongein.xyz +wss://squeet.me +wss://mastodon.org.uk +wss://guild.pmdcollab.org +wss://relay.fi +wss://black.nostrscity.club +wss://relay.darker.to +wss://denostr.paiya.app +wss://noste.lu.ke +wss://wss.node01.nostress.cc +wss://theverge.space +wss://swiss.social +wss://relay.webstr.org +wss://nostr.shsbt.xyz +wss://relay.nostr.mom +wss://bitcoinmaximlaists.online +wss://relay.openhoofd.nl +wss://toot.aquilenet.fr +wss://toot.ale.gd +wss://relay.devstr.org +wss://lounge.town +wss://amala.schwartzwelt.xyz +wss://planetasieve.com.br +wss://alcrypt.ru:20911 +wss://webzero.grin.plus:8080 +wss://pylons.lightlns.com:28556 +wss://etourneau.fr:28343 +wss://sentie.relay.rts.network +wss://hermes.boarstudios.com +wss://non-central.pw +wss://nostrum.casa +wss://press.coop +wss://neovibe.app +wss://mstdn.starnix.network +wss://nostr.ameristraliagov.com +wss://cryptodon.chat +wss://umbrell.local:4848 +wss://mastodon.codingfield.com +wss://fe.disroot.org +wss://national.catposting.agency +wss://mastodon.pinewoodroad.net +wss://podcasts.social +wss://20nostr.semisol.dev +wss://nostr.oxtr.net +wss://mstdn.o-nature-culture.net +wss://dearcoati6.lnbits.com +wss://die-partei.social +wss://donotban.com +wss://creative.ai +wss://metaskey.net +wss://spacey.space +wss://node01.nostreess.cc +wss://node01.nostress.co +wss://niscii.xyz +wss://3gkpphcfwb6w5iq6axnmlbvr7pz2t37uy4ofocyijzttzrbz4jy43fid.onion +wss://3gkpphcfwb6w5iq6axnmlbvr7pz2t37uy4ofocyijzttzrbz4jy43fid.local +wss://sportsbots.xyz +wss://videos.lukesmith.xyz +wss://nostr.btcfreedom.ca +wss://gardenstate.social +wss://bg-btc.local:4848 +wss://0fa53e299287.ngrok.app +wss://bird.makeup +wss://nlayer.lbdev.fun +wss://relay.queiroz.vip +wss://mstdn.business +wss://osage.moe +wss://botrelay.com +wss://filter.wine +wss://gingadon.com +wss://noncentral.pw +wss://honi.club +wss://xn--baw-joa.social +wss://nostr.semisol.devwss +wss://relay.iris.to +wss://mynostrrelay.deno.dev +wss://social.heise.de +wss://vavursybkbgfyow7nnst5jnqsj2xyteusf3zeerbjdizq6y7h25v4syd.onion:5051 +wss://vavursybkbgfyow7nnst5jnqsj2xyteusf3zeerbjdizq6y7h25v4syd.onion:5050 +wss://relao.nostr.bg +wss://phpc.social +wss://mastodon.kylerank.in +wss://gameliberty.club +wss://rot.gives +wss://www.nostrweb.xyz +wss://ligma.pro +wss://mastodon.grin.hu +wss://geeknews.chat +wss://devdilettante.com +wss://relay.nosr-latam.link +wss://nosr.bitcoiner.social +wss://raru.re +wss://create-key.net +wss://lgbtqia.space +wss://fluffy.family +wss://mas.town +wss://bird.froth.zone +wss://akkoma.cryptoschizo.club +wss://relay.ramus.io +wss://40two.site +wss://relay.40two.site +wss://vis.social +wss://mk.paritybit.ca +wss://nyan.network +wss://ln.weedstr.net +wss://wikis.world +wss://social.fringe.com +wss://umbraxenu.no-ip.biz +wss://heads.social +wss://tsqdakwo4dh5ej3llsi52ftxfbialteu3jm4cmvxaksl3psbyeoyxxqd.onion +wss://jameliris.to +wss://mastodon.thirring.org +wss://miniwa.moe +wss://welcom.nostr.wine +wss://nostr.vulpem.comwss +wss://relay.semisol.dev +wss://kitsunes.club +wss://songbird.cloud +wss://nostr.wyssblitz.org +wss://libera.tokyo +wss://trpger.us +wss://comam.es +wss://nostr-pub.semisol.devaddittoyourrel +wss://social.dev-wiki.de +wss://ostfrie.se +wss://darmstadt.social +wss://nostr.cx.ms +wss://alentours.cc +wss://nostr.kleofash.eu +wss://gib.social +wss://test23.hifish.org +wss://rapemeat.solutions +wss://filter.stealth.winebroadcasttrue +wss://nostr.montre +wss://grumble.social +wss://nostr.roli.social +wss://primarycare.app +wss://hodlr.rocks +wss://superlinks.me +wss://mastodon.lawprofs.org +wss://tictoc.social +wss://nostest.dojotunnel.online +wss://kafka.icu +wss://nostr.lanparty.one +wss://filter.nostr.wineglobaltrue +wss://social.b10m.net +wss://worm.pink +wss://nostr-test.cx.ms +wss://nostrverifired.com +wss://relay.nostrss.re +wss://eliitin-some.fi +wss://dju.social +wss://jeremy.hu +wss://stream.criminallycute.fi +wss://nostr.0x50.dev +wss://n.s.nyc +wss://n.8.s.nyc +wss://relay.rocks +wss://relay.fiatjaf.com +wss://n-lan.s.nyc +wss://sciences.social +wss://nostr.swiss-enigma.com +wss://quietplace.xyz +wss://universe.nostrich.landlangenlangzh +wss://5280.city +wss://feddit.de +wss://base.lc +wss://social.medusmedia.com +wss://umha4zl6xk62a4dous6e7tq4qlmt462hlzs2su33en6qrvtvs3hkjgid.onion +wss://etorneau.fr:28343 +wss://foggyminds.com +wss://neurodiversity-in.au +wss://nostr.hendrixson.net +wss://ramen-fsm.eu.org +wss://www.nostrical.com +wss://feedbeat.me +wss://relay.bsky.social +wss://babka.social +wss://mastodontech.de +wss://commiespace.duckdns.org +wss://openbiblio.social +wss://karkatdyinginagluetrap.com +wss://relay.fundr.vanderwarker.family +wss://hannover.town +wss://nostr.relay.info +wss://mastodon.tetaneutral.net +wss://cache2.primal.net +wss://nostr.petrkr.net +wss://ifwo.eu +wss://mastodong.lol +wss://venera.social +wss://wallets.fyoumoneypod.com +wss://nostr.relay-nokotaro.com +wss://social.exozy.me +wss://gqgjp2bun4opme6mepz3rrgprkw4xatb6h5ogayorqwi6sajsxcp5sad.local +wss://branle.netlify.app +wss://rsslay.fiat.jaf +wss://chrislace.damus.io +wss://relay.leafbodhi.com +wss://social.opendesktop.org +wss://relay.nostr.watch +wss://gearlandia.haus +wss://freiburg.social +wss://atlas.nostro.land +wss://nostr.io +wss://patrizio.tn.al +wss://chaintools.io +wss://kn.icu +wss://relaywithme.eu +wss://la-autopilot-this-end-up.dvm.email +wss://coinfinity.co +wss://assemblag.es +wss://qou7zzll2mxx2ehl73n6pptmhizl5b3entowljlin3sqhcvltxdtlmad.onion +wss://indigenouscreatives.social +wss://bookwyrm.social +wss://kokoro.shugetsu.space +wss://eden.nost.land +wss://misskey.gothloli.club +wss://sersleepy.com +wss://rsslay.nos.pink +wss://pettingzoo.co +wss://witches.live +wss://7craxnzfi42touzi23etut5qjzqro27sqcuottxj7opntcin4fstruad.onion +wss://mastodonsweden.se +wss://mv2k.com +wss://nostr.tchaicap.space +wss://relay.whoop.ph +wss://bitcoiner.nostr.social +wss://kinkyelephant.com +wss://www.superstork.org +wss://mastodon.iftas.org +wss://lea.pet +wss://zug.network +wss://homeserver.local:4848 +wss://frontrange.co +wss://sciencemastodon.com +wss://montereybay.social +wss://social.securecryptomining.com +wss://rssrelay.nostr.moe +wss://nostr.org +wss://nostr.tw +wss://nostr.hk +wss://wxw.moe +wss://mastodonmusic.social +wss://puntarella.party +wss://oyasumi.space +wss://drumstodon.net +wss://social.wikimedia.de +wss://iyasaretai.pw +wss://social.coletivos.org +wss://nostream.localtest.me +wss://ubuntu201.local:4848 +wss://masto.pt +wss://taiwan.riley-tech.net +wss://freeradical.zone +wss://blastrf7z.xyz +wss://onemorestop.photo +wss://frikiverse.zone +wss://toot.bldrweb.org +wss://electroverse.tech +wss://mstdn.games +wss://relay1.nostr.unitedfop.com +wss://gratefuldread.masto.host +wss://mk.gabe.rocks +wss://widerweb.org +wss://mastodon.eternalaugust.com +wss://lay.southeastasia.cloudapp.azure.com:445 +wss://me.ns.ci +wss://gnostr.th +wss://fritter.cn +wss://nex.cn +wss://nex.tw +wss://fritter.jp +wss://fritter.tw +wss://gnostr.cn +wss://mstdn.dk +wss://akkoma.simulacrum-emporium.eu +wss://dalliance.social +wss://toot.re +wss://avatastic.uk +wss://blastr20f7z.xyz +wss://the.voiceover.bar +wss://porcodon.net +wss://nostr.dncn.xyz +wss://nostr.dnxn.xyz +wss://relay.xmr.rocks +wss://d6egak3woofrixu26gr3utb5qezhkktavsuwlrfqaauu55lmpudxudqd.onion:5051 +wss://social.wuebbsy.com +wss://4kgwkcfzea2xhefsquktyxqyjf3rsxa7oo7hxbcs6k3xdpxznknydsqd.local +wss://4kgwkcfzea2xhefsquktyxqyjf3rsxa7oo7hxbcs6k3xdpxznknydsqd.onion +wss://tooters.org +wss://nostre.wine +wss://relay.xplive.local +wss://relay2.xplive.local +wss://4v5umvicfs6a7d3aiy67uu2ibttiuanl2cehfmv5qaorbojousbgkdad.onion +wss://pipou.academy +wss://opjk6jxrcyicuwhe62tqy6zwx776u7rfi6cqo6iodurjvege7piz5wqd.local +wss://mythology.social +wss://nostr.millou.lol +wss://ryogrid.net:7777 +wss://nost.debancariser.com +wss://fault.stsecurity.moe +wss://jan-optiplex-5040.local:4848 +wss://relay-jp.wirednet.jp +wss://mastodon.kitchen +wss://relay.mnethome.de +wss://verkehrswende.social +wss://nostr.gleeze.com +wss://dair-community.social +wss://shota.house +wss://kavlak.uk +wss://social.inex.rocks +wss://4v5umvicfs6a7d3aiy67uu2ibttiuanl2cehfmv5qaorbojousbgkdad.local +wss://startrekshitposting.com +wss://nostrfmar.ddns.net +wss://4yqp7gzuf15zfc3hpwhz3j5p2uarvdsnf75ovpdiqvyjdsmku771jfid.onion +wss://nostrgraph.net +wss://idolheaven.org +wss://mstdn.kemono-friends.info +wss://mastodon.bawue.social +wss://social.pmj.rocks +wss://ursal.zone +wss://nstr.milou.lol +wss://poweredbygay.social +wss://gochisou.photo +wss://lnb3.openchain.fr +wss://nostr.filmweb.pl +wss://nostr-word.h3z.jp +wss://blastr.f7z.xyzanotherinstanceofblastr +wss://shakedown.social +wss://nostr.bubu.hair +wss://hyper-nostr.inosta.cc +wss://ieji.de +wss://wawmartme.com +wss://nostr.kungfu-g.rip +wss://bozgor.org +wss://todon.nl +wss://nostpy.lol +wss://ostatus.taiyolab.com +wss://polsum.rocks +wss://freespeech.group +wss://im.allmendenetz.de +wss://shitpost.poridge.club +wss://twingyeo.kr +wss://social.platypush.tech +wss://rsslay-production-bc22.up.railway.app +wss://lonely.damus.io +wss://kirche.social +wss://cubalibre.social +wss://relay.txinito.xyz +wss://realy.orangepill.dev +wss://3zi.ru +wss://plebstr.com +wss://social.seattle.wa.us +wss://social.bim.land +wss://cubhub.social +wss://relay.nostr-x.com +wss://hispagatos.space +wss://node101.nostress.cc +wss://lsbt.me +wss://jgqaglhautb4k6e6i2g34jakxiemqp6z4wynlirltuukgkft2xuglmqd.onion +wss://nostdemo.dojotunnel.online +wss://f.cz \ No newline at end of file diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/core/OptimizedJsonMapper.jvmAndroid.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/core/OptimizedJsonMapper.jvmAndroid.kt new file mode 100644 index 0000000000..ab925260ce --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/core/OptimizedJsonMapper.jvmAndroid.kt @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.core + +import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper + +actual object OptimizedJsonMapper { + fun runCatching(parsingAction: () -> T): T = + try { + parsingAction() + // wraps jackson errors + } catch (e: com.fasterxml.jackson.core.JsonParseException) { + throw IllegalArgumentException(e.message, e) + } + + actual fun fromJson(json: String): Event = runCatching { JacksonMapper.fromJson(json) } + + actual fun toJson(event: Event) = JacksonMapper.toJson(event) + + actual fun fromJsonToTagArray(json: String): Array> = runCatching { JacksonMapper.fromJsonToTagArray(json) } + + actual fun toJson(tags: Array>): String = JacksonMapper.toJson(tags) + + actual inline fun fromJsonTo(json: String): T = runCatching { JacksonMapper.fromJsonTo(json) } + + actual fun toJson(value: OptimizedSerializable): String = JacksonMapper.toJson(value) +} diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasherSerializer.jvmAndroid.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasherSerializer.jvmAndroid.kt new file mode 100644 index 0000000000..db201a94b5 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/crypto/EventHasherSerializer.jvmAndroid.kt @@ -0,0 +1,114 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.crypto + +import com.fasterxml.jackson.core.JsonEncoding +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.JsonProcessingException +import com.fasterxml.jackson.core.util.BufferRecycler +import com.fasterxml.jackson.core.util.ByteArrayBuilder +import com.fasterxml.jackson.databind.JsonMappingException +import com.fasterxml.jackson.databind.node.ArrayNode +import com.fasterxml.jackson.databind.node.JsonNodeFactory +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper +import java.io.IOException + +actual object EventHasherSerializer { + fun makeJsonObjectForId( + pubKey: HexKey, + createdAt: Long, + kind: Int, + tags: Array>, + content: String, + ): ArrayNode { + val factory = JsonNodeFactory.instance + return factory.arrayNode(6).apply { + add(0) + add(pubKey) + add(createdAt) + add(kind) + add( + factory.arrayNode(tags.size).apply { + tags.forEach { tag -> + add( + factory.arrayNode(tag.size).apply { tag.forEach { add(it) } }, + ) + } + }, + ) + add(content) + } + } + + actual fun makeJsonForId( + pubKey: HexKey, + createdAt: Long, + kind: Int, + tags: Array>, + content: String, + ): String = JacksonMapper.toJson(makeJsonObjectForId(pubKey, createdAt, kind, tags, content)) + + actual fun fastMakeJsonForId( + pubKey: HexKey, + createdAt: Long, + kind: Int, + tags: Array>, + content: String, + ): ByteArray { + val br: BufferRecycler = JacksonMapper.mapper.factory._getBufferRecycler() + try { + ByteArrayBuilder(br).use { bb -> + val generator = JacksonMapper.mapper.createGenerator(bb, JsonEncoding.UTF8) + generator.enable(JsonGenerator.Feature.COMBINE_UNICODE_SURROGATES_IN_UTF8) + generator.use { + it.writeStartArray() + it.writeNumber(0) + it.writeString(pubKey) + it.writeNumber(createdAt) + it.writeNumber(kind) + it.writeStartArray() + tags.forEach { tag -> + it.writeStartArray() + tag.forEach { value -> + it.writeString(value) + } + it.writeEndArray() + } + it.writeEndArray() + it.writeString(content) + it.writeEndArray() + } + + val result = bb.toByteArray() + bb.release() + return result + } + } catch (e: JsonProcessingException) { + throw e + } catch (e: IOException) { + // shouldn't really happen, but is declared as possibility so: + throw JsonMappingException.fromUnexpectedIOE(e) + } finally { + br.releaseToPool() + } + } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializer.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializer.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventManualDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventManualDeserializer.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventManualDeserializer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventManualDeserializer.kt index f5cadf3be8..ec704d3563 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventManualDeserializer.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventManualDeserializer.kt @@ -21,8 +21,8 @@ package com.vitorpamplona.quartz.nip01Core.jackson import com.fasterxml.jackson.databind.JsonNode -import com.vitorpamplona.quartz.EventFactory import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.utils.EventFactory class EventManualDeserializer { companion object { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventManualSerializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventManualSerializer.kt similarity index 97% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventManualSerializer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventManualSerializer.kt index 5351028e0a..ccef964d48 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventManualSerializer.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventManualSerializer.kt @@ -67,7 +67,7 @@ class EventManualSerializer { sig: String, ): String { val obj = assemble(id, pubKey, createdAt, kind, tags, content, sig) - return JsonMapper.mapper.writeValueAsString(obj) + return JacksonMapper.mapper.writeValueAsString(obj) } } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventSerializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventSerializer.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventSerializer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/EventSerializer.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/InliningTagArrayPrettyPrinter.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/InliningTagArrayPrettyPrinter.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/InliningTagArrayPrettyPrinter.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/InliningTagArrayPrettyPrinter.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonExt.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonExt.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonExt.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonExt.kt diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapper.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapper.kt new file mode 100644 index 0000000000..a57fcf79d3 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapper.kt @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.jackson + +import com.fasterxml.jackson.core.json.JsonReadFeature +import com.fasterxml.jackson.databind.DeserializationFeature +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.node.ArrayNode +import com.fasterxml.jackson.databind.node.ObjectNode +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.nip01Core.core.OptimizedSerializable +import com.vitorpamplona.quartz.nip01Core.core.TagArray +import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.Message +import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.MessageDeserializer +import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.MessageSerializer +import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.Command +import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.CommandDeserializer +import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.CommandSerializer +import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter +import com.vitorpamplona.quartz.nip01Core.relay.filters.FilterDeserializer +import com.vitorpamplona.quartz.nip01Core.relay.filters.FilterSerializer +import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate +import com.vitorpamplona.quartz.nip01Core.signers.EventTemplateDeserializer +import com.vitorpamplona.quartz.nip01Core.signers.EventTemplateSerializer +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerMessage +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequest +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse +import com.vitorpamplona.quartz.nip46RemoteSigner.jackson.BunkerMessageDeserializer +import com.vitorpamplona.quartz.nip46RemoteSigner.jackson.BunkerRequestDeserializer +import com.vitorpamplona.quartz.nip46RemoteSigner.jackson.BunkerRequestSerializer +import com.vitorpamplona.quartz.nip46RemoteSigner.jackson.BunkerResponseDeserializer +import com.vitorpamplona.quartz.nip46RemoteSigner.jackson.BunkerResponseSerializer +import com.vitorpamplona.quartz.nip47WalletConnect.Request +import com.vitorpamplona.quartz.nip47WalletConnect.Response +import com.vitorpamplona.quartz.nip47WalletConnect.jackson.RequestDeserializer +import com.vitorpamplona.quartz.nip47WalletConnect.jackson.ResponseDeserializer +import com.vitorpamplona.quartz.nip59Giftwrap.rumors.Rumor +import com.vitorpamplona.quartz.nip59Giftwrap.rumors.jackson.RumorDeserializer +import com.vitorpamplona.quartz.nip59Giftwrap.rumors.jackson.RumorSerializer +import java.io.InputStream +import kotlin.jvm.java + +class JacksonMapper { + companion object { + val defaultPrettyPrinter = InliningTagArrayPrettyPrinter() + + val mapper = + jacksonObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature()) + .setDefaultPrettyPrinter(defaultPrettyPrinter) + .registerModule( + SimpleModule() + // nip 01 + .addSerializer(Event::class.java, EventSerializer()) + .addDeserializer(Event::class.java, EventDeserializer()) + .addSerializer(Filter::class.java, FilterSerializer()) + .addDeserializer(Filter::class.java, FilterDeserializer()) + .addSerializer(Message::class.java, MessageSerializer()) + .addDeserializer(Message::class.java, MessageDeserializer()) + .addSerializer(Command::class.java, CommandSerializer()) + .addDeserializer(Command::class.java, CommandDeserializer()) + .addDeserializer(TagArray::class.java, TagArrayDeserializer()) + .addSerializer(TagArray::class.java, TagArraySerializer()) + .addDeserializer(EventTemplate::class.java, EventTemplateDeserializer()) + .addSerializer(EventTemplate::class.java, EventTemplateSerializer()) + // nip 59 + .addSerializer(Rumor::class.java, RumorSerializer()) + .addDeserializer(Rumor::class.java, RumorDeserializer()) + // nip 47 + .addDeserializer(Response::class.java, ResponseDeserializer()) + .addDeserializer(Request::class.java, RequestDeserializer()) + // nip 46 + .addDeserializer(BunkerMessage::class.java, BunkerMessageDeserializer()) + .addSerializer(BunkerRequest::class.java, BunkerRequestSerializer()) + .addDeserializer(BunkerRequest::class.java, BunkerRequestDeserializer()) + .addSerializer(BunkerResponse::class.java, BunkerResponseSerializer()) + .addDeserializer(BunkerResponse::class.java, BunkerResponseDeserializer()), + ) + + fun fromJson(json: String): Event = mapper.readValue(json) + + fun fromJson(json: JsonNode): Event = EventManualDeserializer.fromJson(json) + + fun fromJsonToTagArray(json: String): Array> = mapper.readValue>>(json) + + inline fun fromJsonTo(json: String): T = mapper.readValue(json) + + inline fun fromJsonTo(json: InputStream): T = mapper.readValue(json) + + fun toJson(event: Event): String = EventManualSerializer.toJson(event.id, event.pubKey, event.createdAt, event.kind, event.tags, event.content, event.sig) + + fun toJson(event: ArrayNode): String = mapper.writeValueAsString(event) + + fun toJson(event: ObjectNode?): String = mapper.writeValueAsString(event) + + fun toJson(value: OptimizedSerializable): String = mapper.writeValueAsString(value) + + fun toJson(tags: Array>): String = mapper.writeValueAsString(tags) + } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArrayDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArrayDeserializer.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArrayDeserializer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArrayDeserializer.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArrayManualDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArrayManualDeserializer.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArrayManualDeserializer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArrayManualDeserializer.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArraySerializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArraySerializer.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArraySerializer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/TagArraySerializer.kt diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/MessageDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/MessageDeserializer.kt new file mode 100644 index 0000000000..449043ce57 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/MessageDeserializer.kt @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.relay.commands.toClient + +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.core.JsonToken +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.vitorpamplona.quartz.nip01Core.jackson.EventManualDeserializer + +class MessageDeserializer : StdDeserializer(Message::class.java) { + override fun deserialize( + jp: JsonParser, + ctxt: DeserializationContext, + ): Message? { + // Expect to start with a JSON array token + if (jp.currentToken != JsonToken.START_ARRAY) { + ctxt.reportWrongTokenException(this, JsonToken.START_ARRAY, "Expected START_ARRAY token") + } + + val type = jp.nextTextValue() + val message = + when (type) { + EventMessage.LABEL -> { + val subId = jp.nextTextValue() + jp.nextToken() + val event: JsonNode = jp.codec.readTree(jp) + + EventMessage( + subId = subId, + event = EventManualDeserializer.fromJson(event), + ) + } + EoseMessage.LABEL -> + EoseMessage( + subId = jp.nextTextValue(), + ) + NoticeMessage.LABEL -> + NoticeMessage( + message = jp.nextTextValue(), + ) + OkMessage.LABEL -> + OkMessage( + eventId = jp.nextTextValue(), + success = jp.nextBooleanValue(), + message = jp.nextTextValue() ?: "", + ) + AuthMessage.LABEL -> + AuthMessage( + challenge = jp.nextTextValue(), + ) + NotifyMessage.LABEL -> + NotifyMessage( + message = jp.nextTextValue(), + ) + ClosedMessage.LABEL -> + ClosedMessage( + subId = jp.nextTextValue(), + message = jp.nextTextValue(), + ) + else -> { + throw IllegalArgumentException("Message $type is not supported") + } + } + + if (jp.currentToken != JsonToken.END_ARRAY) { + // cleaning out other array elements + while (jp.nextToken() != JsonToken.END_ARRAY) { + // clears out + } + } + + return message + } +} diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/MessageSerializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/MessageSerializer.kt new file mode 100644 index 0000000000..83da81ef6b --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/MessageSerializer.kt @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.relay.commands.toClient + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.vitorpamplona.quartz.nip01Core.jackson.EventSerializer + +class MessageSerializer : StdSerializer(Message::class.java) { + val eventSerializer = EventSerializer() + + override fun serialize( + msg: Message, + gen: JsonGenerator, + provider: SerializerProvider, + ) { + gen.writeStartArray() + gen.writeString(msg.label()) + + when (msg) { + is EventMessage -> { + gen.writeString(msg.subId) + eventSerializer.serialize(msg.event, gen, provider) + } + + is NoticeMessage -> { + gen.writeString(msg.message) + } + + is OkMessage -> { + gen.writeString(msg.eventId) + gen.writeString(msg.success.toString()) + if (msg.message.isNotBlank()) { + gen.writeString(msg.message) + } + } + + is AuthMessage -> { + gen.writeString(msg.challenge) + } + + is NotifyMessage -> { + gen.writeString(msg.message) + } + + is ClosedMessage -> { + gen.writeString(msg.subId) + gen.writeString(msg.message) + } + + else -> null + } + + gen.writeEndArray() + } +} diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CommandDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CommandDeserializer.kt new file mode 100644 index 0000000000..1ae9543a65 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CommandDeserializer.kt @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.relay.commands.toRelay + +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.core.JsonToken +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.fasterxml.jackson.databind.node.ObjectNode +import com.vitorpamplona.quartz.nip01Core.jackson.EventManualDeserializer +import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter +import com.vitorpamplona.quartz.nip01Core.relay.filters.ManualFilterDeserializer +import com.vitorpamplona.quartz.nip42RelayAuth.RelayAuthEvent + +class CommandDeserializer : StdDeserializer(Command::class.java) { + override fun deserialize( + jp: JsonParser, + ctxt: DeserializationContext, + ): Command? { + // Expect to start with a JSON array token + if (jp.currentToken != JsonToken.START_ARRAY) { + ctxt.reportWrongTokenException(this, JsonToken.START_ARRAY, "Expected START_ARRAY token") + } + + val type = jp.nextTextValue() + val message = + when (type) { + ReqCmd.LABEL -> { + val subId = jp.nextTextValue() + val filters = mutableListOf() + + while (jp.nextToken() != JsonToken.END_ARRAY) { + val filterObj: ObjectNode = jp.codec.readTree(jp) + val filter = ManualFilterDeserializer.fromJson(filterObj) + filters.add(filter) + } + + ReqCmd( + subId = jp.nextTextValue(), + filters = filters, + ) + } + + CountCmd.LABEL -> { + val subId = jp.nextTextValue() + val filters = mutableListOf() + + while (jp.nextToken() != JsonToken.END_ARRAY) { + val filterObj: ObjectNode = jp.codec.readTree(jp) + val filter = ManualFilterDeserializer.fromJson(filterObj) + filters.add(filter) + } + + CountCmd( + subId = subId, + filters = filters, + ) + } + + EventCmd.LABEL -> { + jp.nextToken() + val event: JsonNode = jp.codec.readTree(jp) + + EventCmd( + event = EventManualDeserializer.fromJson(event), + ) + } + + CloseCmd.LABEL -> + CloseCmd( + subId = jp.nextTextValue(), + ) + + AuthCmd.LABEL -> { + jp.nextToken() + val event: JsonNode = jp.codec.readTree(jp) + AuthCmd( + event = EventManualDeserializer.fromJson(event) as RelayAuthEvent, + ) + } + + else -> { + throw IllegalArgumentException("Message $type is not supported") + } + } + + if (jp.currentToken != JsonToken.END_ARRAY) { + // cleaning out other array elements + while (jp.nextToken() != JsonToken.END_ARRAY) { + // clears out + } + } + + return message + } +} diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CommandSerializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CommandSerializer.kt new file mode 100644 index 0000000000..47775b8509 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toRelay/CommandSerializer.kt @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.relay.commands.toRelay + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.vitorpamplona.quartz.nip01Core.jackson.EventSerializer +import com.vitorpamplona.quartz.nip01Core.relay.filters.FilterSerializer + +class CommandSerializer : StdSerializer(Command::class.java) { + val eventSerializer = EventSerializer() + val filterSerializer = FilterSerializer() + + override fun serialize( + cmd: Command, + gen: JsonGenerator, + provider: SerializerProvider, + ) { + gen.writeStartArray() + gen.writeString(cmd.label()) + + when (cmd) { + is ReqCmd -> { + gen.writeString(cmd.subId) + cmd.filters.forEach { + filterSerializer.serialize(it, gen, provider) + } + } + + is EventCmd -> { + eventSerializer.serialize(cmd.event, gen, provider) + } + + is CloseCmd -> { + gen.writeString(cmd.subId) + } + + is AuthCmd -> { + eventSerializer.serialize(cmd.event, gen, provider) + } + + is CountCmd -> { + gen.writeString(cmd.subId) + cmd.filters.forEach { + filterSerializer.serialize(it, gen, provider) + } + } + + else -> null + } + + gen.writeEndArray() + } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt similarity index 82% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt index dc224815d5..273a1da623 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt @@ -20,9 +20,19 @@ */ package com.vitorpamplona.quartz.nip01Core.relay.filters +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.deser.std.StdDeserializer import com.fasterxml.jackson.databind.node.ObjectNode -class FilterDeserializer { +class FilterDeserializer : StdDeserializer(Filter::class.java) { + override fun deserialize( + jp: JsonParser, + ctxt: DeserializationContext, + ): Filter = ManualFilterDeserializer.fromJson(jp.codec.readTree(jp)) +} + +class ManualFilterDeserializer { companion object { fun fromJson(jsonObject: ObjectNode): Filter { val tags = mutableListOf() diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterSerializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterSerializer.kt new file mode 100644 index 0000000000..17f64c17f7 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterSerializer.kt @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.relay.filters + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.ser.std.StdSerializer + +class FilterSerializer : StdSerializer(Filter::class.java) { + override fun serialize( + filter: Filter, + gen: JsonGenerator, + provider: SerializerProvider, + ) { + gen.writeStartObject() + + filter.ids?.run { + gen.writeArrayFieldStart("ids") + for (i in indices) { + gen.writeString(this[i]) + } + gen.writeEndArray() + } + + filter.authors?.run { + gen.writeArrayFieldStart("authors") + for (i in indices) { + gen.writeString(this[i]) + } + gen.writeEndArray() + } + + filter.kinds?.run { + gen.writeArrayFieldStart("kinds") + for (i in indices) { + gen.writeNumber(this[i]) + } + gen.writeEndArray() + } + + filter.tags?.run { + entries.forEach { kv -> + gen.writeArrayFieldStart("#${kv.key}") + for (i in kv.value.indices) { + gen.writeString(kv.value[i]) + } + gen.writeEndArray() + } + } + + filter.since?.run { gen.writeNumberField("since", this) } + filter.until?.run { gen.writeNumberField("until", this) } + filter.limit?.run { gen.writeNumberField("limit", this) } + filter.search?.run { gen.writeStringField("search", this) } + + gen.writeEndObject() + } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/okhttp/BasicOkHttpWebSocket.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/okhttp/BasicOkHttpWebSocket.kt similarity index 85% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/okhttp/BasicOkHttpWebSocket.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/okhttp/BasicOkHttpWebSocket.kt index 12b1f07fa7..685c17d864 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/okhttp/BasicOkHttpWebSocket.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/sockets/okhttp/BasicOkHttpWebSocket.kt @@ -27,13 +27,15 @@ import com.vitorpamplona.quartz.nip01Core.relay.sockets.WebsocketBuilder import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response +import okhttp3.WebSocket as OkHttpWebSocket +import okhttp3.WebSocketListener as OkHttpWebSocketListener class BasicOkHttpWebSocket( val url: NormalizedRelayUrl, val httpClient: (NormalizedRelayUrl) -> OkHttpClient, val out: WebSocketListener, ) : WebSocket { - private var socket: okhttp3.WebSocket? = null + private var socket: OkHttpWebSocket? = null override fun needsReconnect() = socket == null @@ -41,9 +43,9 @@ class BasicOkHttpWebSocket( val request = Request.Builder().url(url.url).build() val listener = - object : okhttp3.WebSocketListener() { + object : OkHttpWebSocketListener() { override fun onOpen( - webSocket: okhttp3.WebSocket, + webSocket: OkHttpWebSocket, response: Response, ) = out.onOpen( (response.receivedResponseAtMillis - response.sentRequestAtMillis).toInt(), @@ -51,27 +53,27 @@ class BasicOkHttpWebSocket( ) override fun onMessage( - webSocket: okhttp3.WebSocket, + webSocket: OkHttpWebSocket, text: String, ) = out.onMessage(text) override fun onClosing( - webSocket: okhttp3.WebSocket, + webSocket: OkHttpWebSocket, code: Int, reason: String, ) = out.onClosing(code, reason) override fun onClosed( - webSocket: okhttp3.WebSocket, + webSocket: OkHttpWebSocket, code: Int, reason: String, ) = out.onClosed(code, reason) override fun onFailure( - webSocket: okhttp3.WebSocket, + webSocket: OkHttpWebSocket, t: Throwable, - r: Response?, - ) = out.onFailure(t, r?.code, r?.message) + response: Response?, + ) = out.onFailure(t, response?.code, response?.message) } socket = httpClient(url).newWebSocket(request, listener) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplateDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplateDeserializer.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplateDeserializer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplateDeserializer.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplateManualDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplateManualDeserializer.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplateManualDeserializer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplateManualDeserializer.kt diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplateSerializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplateSerializer.kt new file mode 100644 index 0000000000..1f88d05633 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/signers/EventTemplateSerializer.kt @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.signers + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.ser.std.StdSerializer + +class EventTemplateSerializer : StdSerializer>(EventTemplate::class.java) { + override fun serialize( + event: EventTemplate<*>, + gen: JsonGenerator, + provider: SerializerProvider, + ) { + gen.writeStartObject() + gen.writeNumberField("created_at", event.createdAt) + gen.writeNumberField("kind", event.kind) + gen.writeArrayFieldStart("tags") + for (i in event.tags.indices) { + gen.writeStartArray() + for (j in event.tags[i].indices) { + gen.writeString(event.tags[i][j]) + } + gen.writeEndArray() + } + gen.writeEndArray() + gen.writeStringField("content", event.content) + gen.writeEndObject() + } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpBitcoinExplorer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip03Timestamp/okhttp/OkHttpBitcoinExplorer.kt similarity index 79% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpBitcoinExplorer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip03Timestamp/okhttp/OkHttpBitcoinExplorer.kt index 5df44323ae..6452e1c658 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpBitcoinExplorer.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip03Timestamp/okhttp/OkHttpBitcoinExplorer.kt @@ -18,18 +18,20 @@ * 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.quartz.nip03Timestamp.ots.okhttp +package com.vitorpamplona.quartz.nip03Timestamp.okhttp -import android.util.Log -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper import com.vitorpamplona.quartz.nip03Timestamp.ots.BitcoinExplorer import com.vitorpamplona.quartz.nip03Timestamp.ots.BlockHeader +import com.vitorpamplona.quartz.nip03Timestamp.ots.OtsBlockHeightCache import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.UrlException +import com.vitorpamplona.quartz.utils.Log import okhttp3.OkHttpClient import okhttp3.Request +import okhttp3.coroutines.executeAsync class OkHttpBitcoinExplorer( - val baseAPI: String, + val baseUrl: () -> String, val client: OkHttpClient, val cache: OtsBlockHeightCache, ) : BitcoinExplorer { @@ -40,11 +42,12 @@ class OkHttpBitcoinExplorer( * @return the blockheader of the hash * @throws Exception desc */ - override fun block(hash: String): BlockHeader { - cache.cacheHeaders.get(hash)?.let { + override suspend fun block(hash: String): BlockHeader { + cache.getHeader(hash)?.let { return it } + val baseAPI = baseUrl() val url = "$baseAPI/block/$hash" val request = @@ -55,17 +58,17 @@ class OkHttpBitcoinExplorer( .get() .build() - client.newCall(request).execute().use { + return client.newCall(request).execute().use { if (it.isSuccessful) { Log.d("OkHttpBlockstreamExplorer", "$baseAPI/block/$hash") - val jsonObject = jacksonObjectMapper().readTree(it.body.string()) + val jsonObject = JacksonMapper.mapper.readTree(it.body.string()) val merkleRoot = jsonObject["merkle_root"].asText() val time = jsonObject["timestamp"].asInt().toString() val blockHeader = BlockHeader(merkleRoot, hash, time) - cache.cacheHeaders.put(hash, blockHeader) - return blockHeader + cache.putHeader(hash, blockHeader) + blockHeader } else { throw UrlException( "Couldn't open $url: " + it.message + " " + it.code, @@ -82,11 +85,12 @@ class OkHttpBitcoinExplorer( * @throws Exception desc */ @Throws(Exception::class) - override fun blockHash(height: Int): String { - cache.cacheHeights[height]?.let { + override suspend fun blockHash(height: Int): String { + cache.getHeight(height)?.let { return it } + val baseAPI = baseUrl() val url = "$baseAPI/block-height/$height" val request = @@ -96,14 +100,14 @@ class OkHttpBitcoinExplorer( .get() .build() - client.newCall(request).execute().use { + return client.newCall(request).executeAsync().use { if (it.isSuccessful) { val blockHash = it.body.string() Log.d("OkHttpBlockstreamExplorer", "$url $blockHash") - cache.cacheHeights.put(height, blockHash) - return blockHash + cache.putHeight(height, blockHash) + blockHash } else { throw UrlException("Couldn't open $url: " + it.message + " " + it.code) } diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip03Timestamp/okhttp/OkHttpCalendar.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip03Timestamp/okhttp/OkHttpCalendar.kt new file mode 100644 index 0000000000..39da52a398 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip03Timestamp/okhttp/OkHttpCalendar.kt @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2025 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.quartz.nip03Timestamp.okhttp + +import com.vitorpamplona.quartz.nip03Timestamp.ots.RemoteCalendar +import com.vitorpamplona.quartz.nip03Timestamp.ots.StreamDeserializationContext +import com.vitorpamplona.quartz.nip03Timestamp.ots.Timestamp +import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.CommitmentNotFoundException +import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.DeserializationException +import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.ExceededSizeException +import com.vitorpamplona.quartz.nip03Timestamp.ots.exceptions.UrlException +import com.vitorpamplona.quartz.utils.Hex +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.coroutines.executeAsync + +/** + * Class representing remote calendar server interface. + */ +class OkHttpCalendar( + val okHttpClient: (url: String) -> OkHttpClient, +) : RemoteCalendar { + override suspend fun submit( + url: String, + digest: ByteArray, + ): Timestamp { + val url = "$url/digest" + + val mediaType = "application/x-www-form-urlencoded; charset=utf-8".toMediaType() + val requestBody = digest.toRequestBody(mediaType) + + val request = + Request + .Builder() + .header("Accept", "application/vnd.opentimestamps.v1") + .header("Content-Type", "application/x-www-form-urlencoded") + .url(url) + .post(requestBody) + .build() + + val client = okHttpClient(url) + return client.newCall(request).executeAsync().use { + if (it.isSuccessful) { + val ctx = + StreamDeserializationContext( + it.body.bytes(), + ) + Timestamp.deserialize(ctx, digest) + } else { + throw UrlException( + "Failed to open $url", + ) + } + } + } + + override suspend fun getTimestamp( + url: String, + commitment: ByteArray, + ): Timestamp = + try { + val url = url + "/timestamp/" + Hex.encode(commitment) + + val request = + Request + .Builder() + .header("Accept", "application/vnd.opentimestamps.v1") + .header("Content-Type", "application/x-www-form-urlencoded") + .url(url) + .get() + .build() + + val client = okHttpClient(url) + client.newCall(request).executeAsync().use { response -> + withContext(Dispatchers.IO) { + if (response.isSuccessful) { + val ctx = StreamDeserializationContext(response.body.bytes()) + Timestamp.deserialize(ctx, commitment) + } else { + throw CommitmentNotFoundException("Calendar response a status code != 200: " + response.code) + } + } + } + } catch (e: DeserializationException) { + throw e + } catch (e: ExceededSizeException) { + throw e + } catch (e: CommitmentNotFoundException) { + throw e + } catch (e: Exception) { + throw UrlException(e.message) + } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpOtsResolverBuilder.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip03Timestamp/okhttp/OkHttpOtsResolverBuilder.kt similarity index 76% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpOtsResolverBuilder.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip03Timestamp/okhttp/OkHttpOtsResolverBuilder.kt index 39af2cc8ff..09f1a3d590 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip03Timestamp/ots/okhttp/OkHttpOtsResolverBuilder.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip03Timestamp/okhttp/OkHttpOtsResolverBuilder.kt @@ -18,32 +18,27 @@ * 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.quartz.nip03Timestamp.ots.okhttp +package com.vitorpamplona.quartz.nip03Timestamp.okhttp import com.vitorpamplona.quartz.nip03Timestamp.OtsResolver import com.vitorpamplona.quartz.nip03Timestamp.OtsResolverBuilder +import com.vitorpamplona.quartz.nip03Timestamp.ots.OtsBlockHeightCache import okhttp3.OkHttpClient class OkHttpOtsResolverBuilder( + val cache: OtsBlockHeightCache = OtsBlockHeightCache(), val okHttpClient: (url: String) -> OkHttpClient, - val isTorActive: (url: String) -> Boolean, - val cache: OtsBlockHeightCache, ) : OtsResolverBuilder { - fun getAPI(usingTor: Boolean) = - if (usingTor) { - OkHttpBitcoinExplorer.MEMPOOL_API_URL - } else { - OkHttpBitcoinExplorer.BLOCKSTREAM_API_URL - } - override fun build(): OtsResolver = OtsResolver( explorer = OkHttpBitcoinExplorer( - baseAPI = getAPI(usingTor = isTorActive(OkHttpBitcoinExplorer.MEMPOOL_API_URL)), + baseUrl = { + OkHttpBitcoinExplorer.BLOCKSTREAM_API_URL + }, client = okHttpClient(OkHttpBitcoinExplorer.MEMPOOL_API_URL), cache = cache, ), - calendarBuilder = OkHttpCalendarBuilder { okHttpClient(it) }, + calendar = OkHttpCalendar(okHttpClient), ) } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerMessage.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerMessageDeserializer.kt similarity index 63% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerMessage.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerMessageDeserializer.kt index fe7007f797..fe1159b117 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/BunkerMessage.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerMessageDeserializer.kt @@ -18,29 +18,29 @@ * 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.quartz.nip46RemoteSigner +package com.vitorpamplona.quartz.nip46RemoteSigner.jackson import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerMessage +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequest +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse +import kotlin.jvm.java -abstract class BunkerMessage { - abstract fun countMemory(): Int +class BunkerMessageDeserializer : StdDeserializer(BunkerMessage::class.java) { + override fun deserialize( + jp: JsonParser, + ctxt: DeserializationContext, + ): BunkerMessage { + val jsonObject: JsonNode = jp.codec.readTree(jp) + val isRequest = jsonObject.has("method") - class BunkerMessageDeserializer : StdDeserializer(BunkerMessage::class.java) { - override fun deserialize( - jp: JsonParser, - ctxt: DeserializationContext, - ): BunkerMessage { - val jsonObject: JsonNode = jp.codec.readTree(jp) - val isRequest = jsonObject.has("method") - - if (isRequest) { - return jp.codec.treeToValue(jsonObject, BunkerRequest::class.java) - } else { - return jp.codec.treeToValue(jsonObject, BunkerResponse::class.java) - } + if (isRequest) { + return jp.codec.treeToValue(jsonObject, BunkerRequest::class.java) + } else { + return jp.codec.treeToValue(jsonObject, BunkerResponse::class.java) } } } diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerRequestDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerRequestDeserializer.kt new file mode 100644 index 0000000000..701a67ef2c --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerRequestDeserializer.kt @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2025 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.quartz.nip46RemoteSigner.jackson + +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.vitorpamplona.quartz.nip01Core.jackson.toTypedArray +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequest +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestConnect +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestGetPublicKey +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestGetRelays +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestNip04Decrypt +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestNip04Encrypt +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestNip44Decrypt +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestNip44Encrypt +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestPing +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestSign + +class BunkerRequestDeserializer : StdDeserializer(BunkerRequest::class.java) { + override fun deserialize( + jp: JsonParser, + ctxt: DeserializationContext, + ): BunkerRequest { + val jsonObject: JsonNode = jp.codec.readTree(jp) + val id = jsonObject.get("id").asText().intern() + val method = jsonObject.get("method").asText().intern() + val params = jsonObject.get("params")?.toTypedArray { it.asText().intern() } ?: emptyArray() + + return when (method) { + BunkerRequestConnect.METHOD_NAME -> BunkerRequestConnect.parse(id, params) + BunkerRequestGetPublicKey.METHOD_NAME -> BunkerRequestGetPublicKey.parse(id, params) + BunkerRequestGetRelays.METHOD_NAME -> BunkerRequestGetRelays.parse(id, params) + + BunkerRequestNip04Decrypt.METHOD_NAME -> BunkerRequestNip04Decrypt.parse(id, params) + BunkerRequestNip04Encrypt.METHOD_NAME -> BunkerRequestNip04Encrypt.parse(id, params) + BunkerRequestNip44Decrypt.METHOD_NAME -> BunkerRequestNip44Decrypt.parse(id, params) + BunkerRequestNip44Encrypt.METHOD_NAME -> BunkerRequestNip44Encrypt.parse(id, params) + + BunkerRequestPing.METHOD_NAME -> BunkerRequestPing.parse(id, params) + BunkerRequestSign.METHOD_NAME -> BunkerRequestSign.parse(id, params) + else -> BunkerRequest(id, method, params) + } + } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/ToClientParser.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerRequestSerializer.kt similarity index 57% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/ToClientParser.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerRequestSerializer.kt index f324c42c0c..46c0b52eec 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/commands/toClient/ToClientParser.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerRequestSerializer.kt @@ -18,23 +18,28 @@ * 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.quartz.nip01Core.relay.commands.toClient +package com.vitorpamplona.quartz.nip46RemoteSigner.jackson -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequest +import kotlin.collections.forEach -class ToClientParser { - fun parse(newMessage: String): Message? { - val msgArray = JsonMapper.mapper.readTree(newMessage) - val type = msgArray.get(0).asText() - return when (type) { - EventMessage.LABEL -> EventMessage.parse(msgArray) - EoseMessage.LABEL -> EoseMessage.parse(msgArray) - NoticeMessage.LABEL -> NoticeMessage.parse(msgArray) - OkMessage.LABEL -> OkMessage.parse(msgArray) - AuthMessage.LABEL -> AuthMessage.parse(msgArray) - NotifyMessage.LABEL -> NotifyMessage.parse(msgArray) - ClosedMessage.LABEL -> ClosedMessage.parse(msgArray) - else -> null +class BunkerRequestSerializer : StdSerializer(BunkerRequest::class.java) { + override fun serialize( + value: BunkerRequest, + gen: JsonGenerator, + provider: SerializerProvider, + ) { + gen.writeStartObject() + gen.writeStringField("id", value.id) + gen.writeStringField("method", value.method) + gen.writeArrayFieldStart("params") + value.params.forEach { + gen.writeString(it) } + gen.writeEndArray() + gen.writeEndObject() } } diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerResponseDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerResponseDeserializer.kt new file mode 100644 index 0000000000..3cfc25a462 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerResponseDeserializer.kt @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2025 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.quartz.nip46RemoteSigner.jackson + +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseAck +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseGetRelays +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponsePong +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponsePublicKey +import com.vitorpamplona.quartz.utils.Hex + +class BunkerResponseDeserializer : StdDeserializer(BunkerResponse::class.java) { + override fun deserialize( + jp: JsonParser, + ctxt: DeserializationContext, + ): BunkerResponse { + val jsonObject: JsonNode = jp.codec.readTree(jp) + + val id = jsonObject.get("id").asText().intern() + val result = jsonObject.get("result")?.asText() + val error = jsonObject.get("error")?.asText() + + if (error != null) { + return com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseError + .parse(id, result, error) + } + + if (result != null) { + when (result) { + BunkerResponseAck.RESULT -> return BunkerResponseAck.parse(id, result, error) + BunkerResponsePong.RESULT -> return BunkerResponsePong.parse(id, result, error) + else -> { + if (result.length == 64 && Hex.isHex(result)) { + return BunkerResponsePublicKey.parse(id, result) + } + + if (result.get(0) == '{') { + try { + return com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseEvent + .parse(id, result) + } catch (_: Exception) { + } + + try { + return BunkerResponseGetRelays.parse(id, result) + } catch (_: Exception) { + } + } + + return BunkerResponse(id, result, error) + } + } + } + + return BunkerResponse(id, result, error) + } +} diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerResponseSerializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerResponseSerializer.kt new file mode 100644 index 0000000000..688bac475e --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip46RemoteSigner/jackson/BunkerResponseSerializer.kt @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2025 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.quartz.nip46RemoteSigner.jackson + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse + +class BunkerResponseSerializer : StdSerializer(BunkerResponse::class.java) { + override fun serialize( + value: BunkerResponse, + gen: JsonGenerator, + provider: SerializerProvider, + ) { + gen.writeStartObject() + gen.writeStringField("id", value.id) + value.result?.let { gen.writeStringField("result", value.result) } + value.error?.let { gen.writeStringField("error", it) } + gen.writeEndObject() + } +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/RequestDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/jackson/RequestDeserializer.kt similarity index 90% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/RequestDeserializer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/jackson/RequestDeserializer.kt index ce73d51e5a..8dccd3219e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/RequestDeserializer.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/jackson/RequestDeserializer.kt @@ -18,12 +18,14 @@ * 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.quartz.nip47WalletConnect +package com.vitorpamplona.quartz.nip47WalletConnect.jackson import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.vitorpamplona.quartz.nip47WalletConnect.PayInvoiceMethod +import com.vitorpamplona.quartz.nip47WalletConnect.Request class RequestDeserializer : StdDeserializer(Request::class.java) { override fun deserialize( diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/ResponseDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/jackson/ResponseDeserializer.kt similarity index 90% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/ResponseDeserializer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/jackson/ResponseDeserializer.kt index c9c3c1c593..4925588541 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/ResponseDeserializer.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip47WalletConnect/jackson/ResponseDeserializer.kt @@ -18,12 +18,15 @@ * 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.quartz.nip47WalletConnect +package com.vitorpamplona.quartz.nip47WalletConnect.jackson import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.vitorpamplona.quartz.nip47WalletConnect.PayInvoiceErrorResponse +import com.vitorpamplona.quartz.nip47WalletConnect.PayInvoiceSuccessResponse +import com.vitorpamplona.quartz.nip47WalletConnect.Response class ResponseDeserializer : StdDeserializer(Response::class.java) { override fun deserialize( diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/RumorDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/jackson/RumorDeserializer.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/RumorDeserializer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/jackson/RumorDeserializer.kt index 888b64c421..0d50562304 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/RumorDeserializer.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/jackson/RumorDeserializer.kt @@ -18,13 +18,14 @@ * 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.quartz.nip59Giftwrap.rumors +package com.vitorpamplona.quartz.nip59Giftwrap.rumors.jackson import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.deser.std.StdDeserializer import com.vitorpamplona.quartz.nip01Core.jackson.toTypedArray +import com.vitorpamplona.quartz.nip59Giftwrap.rumors.Rumor class RumorDeserializer : StdDeserializer(Rumor::class.java) { override fun deserialize( diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/RumorSerializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/jackson/RumorSerializer.kt similarity index 94% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/RumorSerializer.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/jackson/RumorSerializer.kt index 8c19df501b..81cdbd681d 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/RumorSerializer.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip59Giftwrap/rumors/jackson/RumorSerializer.kt @@ -18,11 +18,12 @@ * 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.quartz.nip59Giftwrap.rumors +package com.vitorpamplona.quartz.nip59Giftwrap.rumors.jackson import com.fasterxml.jackson.core.JsonGenerator import com.fasterxml.jackson.databind.SerializerProvider import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.vitorpamplona.quartz.nip59Giftwrap.rumors.Rumor class RumorSerializer : StdSerializer(Rumor::class.java) { override fun serialize( diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.jvmAndroid.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.jvmAndroid.kt new file mode 100644 index 0000000000..3fa99b9253 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip96FileStorage/info/ServerInfoParser.jvmAndroid.kt @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2025 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.quartz.nip96FileStorage.info + +import java.net.URI +import java.net.URL + +actual fun makeAbsoluteIfRelativeUrl( + baseUrl: String, + potentiallyRelativeUrl: String, +): String = + try { + val apiUrl = URI(potentiallyRelativeUrl) + if (apiUrl.isAbsolute) { + potentiallyRelativeUrl + } else { + URL(URL(baseUrl), potentiallyRelativeUrl).toString() + } + } catch (e: Exception) { + potentiallyRelativeUrl + } diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/BigDecimal.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/BigDecimal.kt new file mode 100644 index 0000000000..2046d581f1 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/BigDecimal.kt @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import java.math.BigDecimal as JBigDecimal + +actual typealias BigDecimal = JBigDecimal diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/BitSet.jvmAndroid.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/BitSet.jvmAndroid.kt new file mode 100644 index 0000000000..01249d3d72 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/BitSet.jvmAndroid.kt @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import java.util.BitSet as JvmBitSet + +actual typealias BitSet = JvmBitSet + +actual fun bitSetValueOf(bytes: ByteArray): BitSet = JvmBitSet.valueOf(bytes) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/GZip.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/GZip.jvmAndroid.kt similarity index 75% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/GZip.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/GZip.jvmAndroid.kt index 8bba32709d..2e3aba3652 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/GZip.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/GZip.jvmAndroid.kt @@ -24,14 +24,12 @@ import java.io.ByteArrayOutputStream import java.util.zip.GZIPInputStream import java.util.zip.GZIPOutputStream -class GZip { - companion object { - fun compress(content: String): ByteArray { - val bos = ByteArrayOutputStream() - GZIPOutputStream(bos).bufferedWriter(Charsets.UTF_8).use { it.write(content) } - return bos.toByteArray() - } - - fun decompress(content: ByteArray): String = GZIPInputStream(content.inputStream()).bufferedReader(Charsets.UTF_8).use { it.readText() } +actual object GZip { + actual fun compress(content: String): ByteArray { + val bos = ByteArrayOutputStream() + GZIPOutputStream(bos).bufferedWriter(Charsets.UTF_8).use { it.write(content) } + return bos.toByteArray() } + + actual fun decompress(content: ByteArray): String = GZIPInputStream(content.inputStream()).bufferedReader(Charsets.UTF_8).use { it.readText() } } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/UriReferenceExt.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/Rfc3986.jvmAndroid.kt similarity index 75% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/UriReferenceExt.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/Rfc3986.jvmAndroid.kt index 4de756818d..01eb3b67e1 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/UriReferenceExt.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/Rfc3986.jvmAndroid.kt @@ -22,6 +22,28 @@ package com.vitorpamplona.quartz.utils import org.czeal.rfc3986.URIReference +actual object Rfc3986 { + actual fun normalize(uri: String) = + URIReference + .parse(uri) + .normalize() + .toString() + + actual fun isValidUrl(url: String): Boolean = + runCatching { + URIReference.parse(url) + }.isSuccess + + actual fun normalizeAndRemoveFragment(url: String): String = + URIReference + .parse(url) + .normalize() + .toStringNoFragment() + .intern() + + actual fun host(url: String): String = URIReference.parse(url).host.value +} + fun URIReference.toStringSchemeHost(): String { val sb = StringBuilder() diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.jvmAndroid.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.jvmAndroid.kt new file mode 100644 index 0000000000..630df6e4de --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/SecureRandom.jvmAndroid.kt @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import java.security.SecureRandom as JvmSecureRandom + +actual typealias SecureRandom = JvmSecureRandom diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/StringExt.jvmAndroid.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/StringExt.jvmAndroid.kt new file mode 100644 index 0000000000..ab98703e2a --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/StringExt.jvmAndroid.kt @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +actual fun String.internIfPossible() = this.intern() diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/UnicodeNormalizer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/UnicodeNormalizer.kt new file mode 100644 index 0000000000..734e9f2693 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/UnicodeNormalizer.kt @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import java.text.Normalizer + +actual class UnicodeNormalizer { + actual fun normalizeNFKC(input: String): String = Normalizer.normalize(input, Normalizer.Form.NFKC) +} diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/UrlEncoder.jvmAndroid.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/UrlEncoder.jvmAndroid.kt new file mode 100644 index 0000000000..f7409a2280 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/UrlEncoder.jvmAndroid.kt @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import java.net.URLDecoder +import java.net.URLEncoder + +actual object UrlEncoder { + actual fun encode(value: String): String = URLEncoder.encode(value, "utf-8") + + actual fun decode(value: String): String = URLDecoder.decode(value, "utf-8") +} diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/Urls.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/Urls.kt new file mode 100644 index 0000000000..877114e2ac --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/Urls.kt @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import com.linkedin.urls.detection.UrlDetector +import com.linkedin.urls.detection.UrlDetectorOptions + +actual fun fastFindURLs(text: String): List = UrlDetector(text, UrlDetectorOptions.Default).detect().map { it.originalUrl } diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/CacheCollectors.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/CacheCollectors.kt similarity index 87% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/CacheCollectors.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/CacheCollectors.kt index 5b54c8be7b..96280f264e 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/CacheCollectors.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/CacheCollectors.kt @@ -18,13 +18,13 @@ * 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.quartz.utils +package com.vitorpamplona.quartz.utils.cache -import com.vitorpamplona.quartz.utils.CacheCollectors.BiFilter -import com.vitorpamplona.quartz.utils.CacheCollectors.BiMapper -import com.vitorpamplona.quartz.utils.CacheCollectors.BiMapperNotNull -import com.vitorpamplona.quartz.utils.CacheCollectors.BiNotNullMapper -import com.vitorpamplona.quartz.utils.CacheCollectors.BiSumOfLong +import com.vitorpamplona.quartz.utils.cache.CacheCollectors.BiFilter +import com.vitorpamplona.quartz.utils.cache.CacheCollectors.BiMapper +import com.vitorpamplona.quartz.utils.cache.CacheCollectors.BiMapperNotNull +import com.vitorpamplona.quartz.utils.cache.CacheCollectors.BiNotNullMapper +import com.vitorpamplona.quartz.utils.cache.CacheCollectors.BiSumOfLong import java.util.function.BiConsumer class BiFilterCollector( @@ -321,47 +321,3 @@ class BiAssociateNotNullWithCollector( } } } - -object CacheCollectors { - fun interface BiFilter { - fun filter( - k: K, - v: V, - ): Boolean - } - - fun interface BiMapper { - fun map( - k: K, - v: V, - ): R? - } - - fun interface BiMapperNotNull { - fun map( - k: K, - v: V, - ): R - } - - fun interface BiNotNullMapper { - fun map( - k: K, - v: V, - ): R - } - - fun interface BiSumOf { - fun map( - k: K, - v: V, - ): Int - } - - fun interface BiSumOfLong { - fun map( - k: K, - v: V, - ): Long - } -} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/CacheOperations.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/CacheOperations.kt similarity index 67% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/CacheOperations.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/CacheOperations.kt index 24e0577079..00a51c43fb 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/CacheOperations.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/CacheOperations.kt @@ -18,58 +18,73 @@ * 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.quartz.utils +package com.vitorpamplona.quartz.utils.cache import java.util.function.BiConsumer -interface CacheOperations { +class MyBiConsumer( + private val consumer: ICacheBiConsumer, +) : BiConsumer { + override fun accept( + k: K, + v: V, + ) { + consumer.accept(k, v) + } +} + +interface CacheOperations : ICacheOperations { fun forEach(consumer: BiConsumer) - fun size(): Int + override fun size(): Int - fun filter(consumer: CacheCollectors.BiFilter): List { + override fun forEach(consumer: ICacheBiConsumer) { + forEach(MyBiConsumer(consumer)) + } + + override fun filter(consumer: CacheCollectors.BiFilter): List { val runner = BiFilterCollector(consumer) forEach(runner) return runner.results } - fun filterIntoSet(consumer: CacheCollectors.BiFilter): Set { + override fun filterIntoSet(consumer: CacheCollectors.BiFilter): Set { val runner = BiFilterUniqueCollector(consumer) forEach(runner) return runner.results } - fun map(consumer: CacheCollectors.BiNotNullMapper): List { + override fun map(consumer: CacheCollectors.BiNotNullMapper): List { val runner = BiNotNullMapCollector(consumer) forEach(runner) return runner.results } - fun mapNotNull(consumer: CacheCollectors.BiMapper): List { + override fun mapNotNull(consumer: CacheCollectors.BiMapper): List { val runner = BiMapCollector(consumer) forEach(runner) return runner.results } - fun mapNotNullIntoSet(consumer: CacheCollectors.BiMapper): Set { + override fun mapNotNullIntoSet(consumer: CacheCollectors.BiMapper): Set { val runner = BiMapUniqueCollector(consumer) forEach(runner) return runner.results } - fun mapFlatten(consumer: CacheCollectors.BiMapper?>): List { + override fun mapFlatten(consumer: CacheCollectors.BiMapper?>): List { val runner = BiMapFlattenCollector(consumer) forEach(runner) return runner.results } - fun mapFlattenIntoSet(consumer: CacheCollectors.BiMapper?>): Set { + override fun mapFlattenIntoSet(consumer: CacheCollectors.BiMapper?>): Set { val runner = BiMapFlattenUniqueCollector(consumer) forEach(runner) return runner.results } - fun maxOrNullOf( + override fun maxOrNullOf( filter: CacheCollectors.BiFilter, comparator: Comparator, ): V? { @@ -78,31 +93,31 @@ interface CacheOperations { return runner.maxV } - fun sumOf(consumer: CacheCollectors.BiSumOf): Int { + override fun sumOf(consumer: CacheCollectors.BiSumOf): Int { val runner = BiSumOfCollector(consumer) forEach(runner) return runner.sum } - fun sumOfLong(consumer: CacheCollectors.BiSumOfLong): Long { + override fun sumOfLong(consumer: CacheCollectors.BiSumOfLong): Long { val runner = BiSumOfLongCollector(consumer) forEach(runner) return runner.sum } - fun groupBy(consumer: CacheCollectors.BiNotNullMapper): Map> { + override fun groupBy(consumer: CacheCollectors.BiNotNullMapper): Map> { val runner = BiGroupByCollector(consumer) forEach(runner) return runner.results } - fun countByGroup(consumer: CacheCollectors.BiNotNullMapper): Map { + override fun countByGroup(consumer: CacheCollectors.BiNotNullMapper): Map { val runner = BiCountByGroupCollector(consumer) forEach(runner) return runner.results } - fun sumByGroup( + override fun sumByGroup( groupMap: CacheCollectors.BiNotNullMapper, sumOf: CacheCollectors.BiNotNullMapper, ): Map { @@ -111,31 +126,31 @@ interface CacheOperations { return runner.results } - fun count(consumer: CacheCollectors.BiFilter): Int { + override fun count(consumer: CacheCollectors.BiFilter): Int { val runner = BiCountIfCollector(consumer) forEach(runner) return runner.count } - fun associate(transform: (K, V) -> Pair): Map { + override fun associate(transform: (K, V) -> Pair): Map { val runner = BiAssociateCollector(size(), transform) forEach(runner) return runner.results } - fun associateWith(transform: (K, V) -> U?): Map { + override fun associateWith(transform: (K, V) -> U?): Map { val runner = BiAssociateWithCollector(size(), transform) forEach(runner) return runner.results } - fun joinToString( - separator: CharSequence = ", ", - prefix: CharSequence = "", - postfix: CharSequence = "", - limit: Int = -1, - truncated: CharSequence = "...", - transform: ((K, V) -> CharSequence)? = null, + override fun joinToString( + separator: CharSequence, + prefix: CharSequence, + postfix: CharSequence, + limit: Int, + truncated: CharSequence, + transform: ((K, V) -> CharSequence)?, ): String { val buffer = StringBuilder() buffer.append(prefix) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/LargeCache.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.jvmAndroid.kt similarity index 78% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/LargeCache.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.jvmAndroid.kt index 962932c9af..6a430bb86c 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/LargeCache.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/cache/LargeCache.jvmAndroid.kt @@ -18,38 +18,38 @@ * 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.quartz.utils +package com.vitorpamplona.quartz.utils.cache import java.util.concurrent.ConcurrentSkipListMap import java.util.function.BiConsumer -class LargeCache : CacheOperations { +actual class LargeCache : CacheOperations { private val cache = ConcurrentSkipListMap() - fun keys() = cache.keys + actual fun keys(): Set = cache.keys - fun values() = cache.values + actual fun values(): Iterable = cache.values - fun get(key: K) = cache.get(key) + actual fun get(key: K) = cache.get(key) - fun remove(key: K) = cache.remove(key) + actual fun remove(key: K) = cache.remove(key) - override fun size() = cache.size + actual override fun size() = cache.size - fun isEmpty() = cache.isEmpty() + actual fun isEmpty() = cache.isEmpty() - fun clear() = cache.clear() + actual fun clear() = cache.clear() - fun containsKey(key: K) = cache.containsKey(key) + actual fun containsKey(key: K) = cache.containsKey(key) - fun put( + actual fun put( key: K, value: V, ) { cache.put(key, value) } - fun getOrCreate( + actual fun getOrCreate( key: K, builder: (key: K) -> V, ): V { @@ -63,7 +63,7 @@ class LargeCache : CacheOperations { } } - fun createIfAbsent( + actual fun createIfAbsent( key: K, builder: (key: K) -> V, ): Boolean { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/AESCBC.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESCBC.jvmAndroid.kt similarity index 78% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/AESCBC.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESCBC.jvmAndroid.kt index 260782dbf8..d938a21e51 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip04Dm/crypto/AESCBC.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESCBC.jvmAndroid.kt @@ -18,19 +18,17 @@ * 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.quartz.nip04Dm.crypto +package com.vitorpamplona.quartz.utils.ciphers -import android.util.Log -import com.vitorpamplona.quartz.nip17Dm.files.encryption.NostrCipher -import com.vitorpamplona.quartz.utils.RandomInstance +import com.vitorpamplona.quartz.utils.Log import java.security.GeneralSecurityException import javax.crypto.Cipher import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.SecretKeySpec -class AESCBC( - val keyBytes: ByteArray = RandomInstance.bytes(32), - val iv: ByteArray = RandomInstance.bytes(16), +actual class AESCBC actual constructor( + actual val keyBytes: ByteArray, + actual val iv: ByteArray, ) : NostrCipher { private fun newCipher() = Cipher.getInstance("AES/CBC/PKCS5Padding") @@ -38,21 +36,21 @@ class AESCBC( private fun param() = IvParameterSpec(iv) - override fun name() = NAME + actual override fun name() = NAME - override fun encrypt(bytesToEncrypt: ByteArray): ByteArray = + actual override fun encrypt(bytesToEncrypt: ByteArray): ByteArray = with(newCipher()) { init(Cipher.ENCRYPT_MODE, keySpec(), param()) doFinal(bytesToEncrypt) } - override fun decrypt(bytesToDecrypt: ByteArray): ByteArray = + actual override fun decrypt(bytesToDecrypt: ByteArray): ByteArray = with(newCipher()) { init(Cipher.DECRYPT_MODE, keySpec(), param()) doFinal(bytesToDecrypt) } - override fun decryptOrNull(bytesToDecrypt: ByteArray): ByteArray? = + actual override fun decryptOrNull(bytesToDecrypt: ByteArray): ByteArray? = try { decrypt(bytesToDecrypt) } catch (e: GeneralSecurityException) { diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/encryption/AESGCM.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.jvmAndroid.kt similarity index 81% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/encryption/AESGCM.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.jvmAndroid.kt index a9ff7b419f..b5c065a611 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip17Dm/files/encryption/AESGCM.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/ciphers/AESGCM.jvmAndroid.kt @@ -18,19 +18,18 @@ * 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.quartz.nip17Dm.files.encryption +package com.vitorpamplona.quartz.utils.ciphers -import android.util.Log import com.vitorpamplona.quartz.nip01Core.core.toHexKey -import com.vitorpamplona.quartz.utils.RandomInstance +import com.vitorpamplona.quartz.utils.Log import java.security.GeneralSecurityException import javax.crypto.Cipher import javax.crypto.spec.GCMParameterSpec import javax.crypto.spec.SecretKeySpec -class AESGCM( - val keyBytes: ByteArray = RandomInstance.bytes(32), - val nonce: ByteArray = RandomInstance.bytes(16), +actual class AESGCM actual constructor( + actual val keyBytes: ByteArray, + actual val nonce: ByteArray, ) : NostrCipher { private fun newCipher() = Cipher.getInstance("AES/GCM/NoPadding") @@ -38,7 +37,7 @@ class AESGCM( private fun param() = GCMParameterSpec(128, nonce) - override fun name() = NAME + actual override fun name() = NAME fun copyUsingUTF8Nonce(): AESGCM = AESGCM( @@ -46,19 +45,19 @@ class AESGCM( nonce.toHexKey().toByteArray(Charsets.UTF_8), ) - override fun encrypt(bytesToEncrypt: ByteArray): ByteArray = + actual override fun encrypt(bytesToEncrypt: ByteArray): ByteArray = with(newCipher()) { init(Cipher.ENCRYPT_MODE, keySpec(), param()) doFinal(bytesToEncrypt) } - override fun decrypt(bytesToDecrypt: ByteArray): ByteArray = + actual override fun decrypt(bytesToDecrypt: ByteArray): ByteArray = with(newCipher()) { init(Cipher.DECRYPT_MODE, keySpec(), param()) doFinal(bytesToDecrypt) } - override fun decryptOrNull(bytesToDecrypt: ByteArray): ByteArray? = + actual override fun decryptOrNull(bytesToDecrypt: ByteArray): ByteArray? = try { decrypt(bytesToDecrypt) } catch (e: GeneralSecurityException) { diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/diggest/DigestInstance.jvmAndroid.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/diggest/DigestInstance.jvmAndroid.kt new file mode 100644 index 0000000000..0da0917b98 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/diggest/DigestInstance.jvmAndroid.kt @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2025 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.quartz.utils.diggest + +import java.security.MessageDigest + +actual class DigestInstance actual constructor( + algorithm: String, +) { + val digest: MessageDigest = MessageDigest.getInstance(algorithm) + + actual fun update(array: ByteArray) = digest.update(array) + + actual fun update(byte: Byte) = digest.update(byte) + + actual fun digest(): ByteArray = digest.digest() + + actual fun digest(input: ByteArray): ByteArray = digest.digest(input) +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/FixedKey.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/mac/FixedKey.kt similarity index 65% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/FixedKey.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/mac/FixedKey.kt index 6f4c21bc65..c46b4496ed 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/nip44Encryption/crypto/FixedKey.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/mac/FixedKey.kt @@ -18,10 +18,13 @@ * 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.quartz.nip44Encryption.crypto +package com.vitorpamplona.quartz.utils.mac import javax.crypto.SecretKey +/** + * Simple key spec that doesn't clone the key bytearray + */ class FixedKey( val key: ByteArray, val algo: String, @@ -32,12 +35,30 @@ class FixedKey( override fun getFormat() = "RAW" - override fun hashCode() = key.contentHashCode() + override fun hashCode() = key.contentHashCode() xor algo.hashCode() override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is FixedKey) return false - return key.contentEquals(other.key) + + if (!key.contentEquals(other.key)) return false + + // Old algorithm names + val thatAlg = other.algorithm + if (!(thatAlg.equals(this.algorithm, ignoreCase = true))) { + if (( + !(thatAlg.equals("DESede", ignoreCase = true)) || + !(this.algorithm.equals("TripleDES", ignoreCase = true)) + ) && + ( + !(thatAlg.equals("TripleDES", ignoreCase = true)) || + !(this.algorithm.equals("DESede", ignoreCase = true)) + ) + ) { + return false + } + } + return true } override fun destroy() = key.fill(0) diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/mac/MacInstance.jvmAndroid.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/mac/MacInstance.jvmAndroid.kt new file mode 100644 index 0000000000..b3135f0498 --- /dev/null +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/mac/MacInstance.jvmAndroid.kt @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2025 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.quartz.utils.mac + +import javax.crypto.Mac + +actual class MacInstance actual constructor( + algorithm: String, + key: ByteArray, +) { + val mac: Mac = + Mac.getInstance(algorithm).apply { + init(FixedKey(key, algorithm)) + } + + actual fun init( + key: ByteArray, + algorithm: String, + ) = mac.init(FixedKey(key, algorithm)) + + actual fun getMacLength() = mac.macLength + + actual fun update(array: ByteArray) = mac.update(array) + + actual fun update(byte: Byte) = mac.update(byte) + + actual fun doFinal() = mac.doFinal() + + actual fun doFinal( + output: ByteArray, + offset: Int, + ) = mac.doFinal(output, offset) +} diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.jvmAndroid.kt similarity index 95% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.jvmAndroid.kt index 7e30261909..c71dae98e9 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256.jvmAndroid.kt @@ -22,4 +22,4 @@ package com.vitorpamplona.quartz.utils.sha256 val pool = Sha256Pool(5) // max parallel operations -fun sha256(data: ByteArray) = pool.hash(data) +actual fun sha256(data: ByteArray) = pool.hash(data) diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256Hasher.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256Hasher.jvmAndroid.kt similarity index 100% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256Hasher.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256Hasher.jvmAndroid.kt diff --git a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256Pool.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256Pool.jvmAndroid.kt similarity index 96% rename from quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256Pool.kt rename to quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256Pool.jvmAndroid.kt index cb0561e8db..6c76f66d4d 100644 --- a/quartz/src/androidMain/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256Pool.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/utils/sha256/Sha256Pool.jvmAndroid.kt @@ -20,7 +20,7 @@ */ package com.vitorpamplona.quartz.utils.sha256 -import android.util.Log +import com.vitorpamplona.quartz.utils.Log import java.util.concurrent.ArrayBlockingQueue class Sha256Pool( @@ -35,7 +35,7 @@ class Sha256Pool( } private fun acquire(): Sha256Hasher { - if (pool.size < 1) { + if (pool.isEmpty()) { Log.w("SHA256Pool", "Pool running low in available digests") } return pool.take() diff --git a/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.jvm.kt b/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.jvm.kt new file mode 100644 index 0000000000..521c0daddc --- /dev/null +++ b/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/Address.jvm.kt @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2025 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.quartz.nip01Core.core + +import com.vitorpamplona.quartz.utils.bytesUsedInMemory +import com.vitorpamplona.quartz.utils.pointerSizeInBytes + +actual data class Address actual constructor( + actual val kind: Kind, + actual val pubKeyHex: HexKey, + actual val dTag: String, +) : Comparable
{ + actual fun toValue() = assemble(kind, pubKeyHex, dTag) + + actual fun countMemory(): Int = + 3 * pointerSizeInBytes + + 8 + // kind + pubKeyHex.bytesUsedInMemory() + + dTag.bytesUsedInMemory() + + actual override fun compareTo(other: Address): Int { + val result = kind.compareTo(other.kind) + return if (result == 0) { + val result2 = pubKeyHex.compareTo(other.pubKeyHex) + if (result2 == 0) { + dTag.compareTo(other.dTag) + } else { + result2 + } + } else { + result + } + } + + actual companion object { + actual fun assemble( + kind: Int, + pubKeyHex: HexKey, + dTag: String, + ) = AddressSerializer.assemble(kind, pubKeyHex, dTag) + + actual fun parse(addressId: String) = AddressSerializer.parse(addressId) + + actual fun isOfKind( + addressId: String, + kind: String, + ) = addressId.startsWith(kind) && addressId[kind.length] == ':' + } +} diff --git a/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.jvm.kt b/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.jvm.kt new file mode 100644 index 0000000000..cb54909bd2 --- /dev/null +++ b/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/LibSodiumInstance.jvm.kt @@ -0,0 +1,104 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import com.goterl.lazysodium.LazySodiumJava +import com.goterl.lazysodium.SodiumJava + +actual object LibSodiumInstance { + private val libSodium = SodiumJava() + private val lazySodium = LazySodiumJava(libSodium) + + actual fun cryptoAeadXChaCha20Poly1305IetfDecrypt( + message: ByteArray, + nSec: ByteArray, + ciphertext: ByteArray, + ad: ByteArray, + nPub: ByteArray, + k: ByteArray, + ): Boolean = + lazySodium.cryptoAeadXChaCha20Poly1305IetfDecrypt( + message, + longArrayOf(message.size.toLong()), + nSec, + ciphertext, + ciphertext.size.toLong(), + ad, + ad.size.toLong(), + nPub, + k, + ) + + actual fun cryptoAeadXChaCha20Poly1305IetfEncrypt( + ciphertext: ByteArray, + message: ByteArray, + ad: ByteArray, + nSec: ByteArray, + nPub: ByteArray, + k: ByteArray, + ): Boolean = + lazySodium.cryptoAeadXChaCha20Poly1305IetfEncrypt( + ciphertext, + longArrayOf(ciphertext.size.toLong()), + message, + message.size.toLong(), + ad, + ad.size.toLong(), + nSec, + nPub, + k, + ) + + actual fun cryptoStreamChaCha20IetfXor( + message: ByteArray, + nonce: ByteArray?, + key: ByteArray?, + ): ByteArray { + val ciphertext = ByteArray(message.size) + lazySodium.cryptoStreamChaCha20IetfXor(ciphertext, message, message.size.toLong(), nonce, key) + return ciphertext + } + + actual fun cryptoStreamXChaCha20Xor( + messageBytes: ByteArray, + nonce: ByteArray, + key: ByteArray, + ): ByteArray { + val cipher = ByteArray(messageBytes.size) + val k2 = ByteArray(32) + + val nonceChaCha = nonce.drop(16).toByteArray() + assert(nonceChaCha.size == 8) + + libSodium.crypto_core_hchacha20(k2, nonce, key, null) + val resultCode = + libSodium.crypto_stream_chacha20_xor_ic( + cipher, + messageBytes, + messageBytes.size.toLong(), + nonceChaCha, + 0, + k2, + ) + + return if (resultCode == 0) cipher else throw IllegalStateException("Could not decrypt message") + } +} diff --git a/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/Log.jvm.kt b/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/Log.jvm.kt new file mode 100644 index 0000000000..29a4cb091a --- /dev/null +++ b/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/Log.jvm.kt @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +actual object Log { + actual fun w( + tag: String, + message: String, + throwable: Throwable?, + ) { + if (throwable != null) { + println("WARN: [$tag] $message. Throwable: ${throwable.message}") + } else { + println("WARN: [$tag] $message") + } + } + + actual fun e( + tag: String, + message: String, + throwable: Throwable?, + ) { + if (throwable != null) { + println("ERROR: [$tag] $message. Throwable: ${throwable.message}") + } else { + println("ERROR: [$tag] $message") + } + } + + actual fun d( + tag: String, + message: String, + ) { + println("DEBUG: [$tag] $message") + } + + actual fun i( + tag: String, + message: String, + ) { + println("INFO: [$tag] $message") + } +} diff --git a/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/Platform.jvm.kt b/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/Platform.jvm.kt similarity index 91% rename from quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/Platform.jvm.kt rename to quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/Platform.jvm.kt index 3bcb460242..b08564336c 100644 --- a/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/Platform.jvm.kt +++ b/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/Platform.jvm.kt @@ -18,6 +18,8 @@ * 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.quartz +package com.vitorpamplona.quartz.utils actual fun platform() = "JVM" + +actual fun currentTimeSeconds() = System.currentTimeMillis() / 1000 diff --git a/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.jvm.kt b/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.jvm.kt new file mode 100644 index 0000000000..c66cb78e06 --- /dev/null +++ b/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/Secp256k1Instance.jvm.kt @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import fr.acinq.secp256k1.Secp256k1 + +actual object Secp256k1Instance { + private val h02 = Hex.decode("02") + private val secp256k1 = Secp256k1.get() + + actual fun compressedPubKeyFor(privKey: ByteArray) = secp256k1.pubKeyCompress(secp256k1.pubkeyCreate(privKey)) + + actual fun isPrivateKeyValid(il: ByteArray): Boolean = secp256k1.secKeyVerify(il) + + actual fun signSchnorr( + data: ByteArray, + privKey: ByteArray, + nonce: ByteArray?, + ): ByteArray = secp256k1.signSchnorr(data, privKey, nonce) + + actual fun signSchnorr( + data: ByteArray, + privKey: ByteArray, + ): ByteArray = secp256k1.signSchnorr(data, privKey, null) + + actual fun verifySchnorr( + signature: ByteArray, + hash: ByteArray, + pubKey: ByteArray, + ): Boolean = secp256k1.verifySchnorr(signature, hash, pubKey) + + actual fun privateKeyAdd( + first: ByteArray, + second: ByteArray, + ): ByteArray = secp256k1.privKeyTweakAdd(first, second) + + actual fun pubKeyTweakMulCompact( + pubKey: ByteArray, + privateKey: ByteArray, + ): ByteArray = secp256k1.pubKeyTweakMul(h02 + pubKey, privateKey).copyOfRange(1, 33) +} diff --git a/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.jvm.kt b/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.jvm.kt new file mode 100644 index 0000000000..fa94a6a438 --- /dev/null +++ b/quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/utils/UriParser.jvm.kt @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2025 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.quartz.utils + +import java.net.URI +import java.net.URLDecoder + +actual class UriParser actual constructor( + uri: String, +) { + val myUri = URI.create(uri) + val queryParameters: Map by lazy { + myUri.query?.ifBlank { null }?.let { query -> + query.split('&').associate { paramValue -> + val parts = paramValue.split("=", limit = 2) + if (parts.size == 2) { + parts[0] to parts[1] + } else { + parts[0] to "" // Handle parameters without a value, e.g., "param&other=value" + } + } + } ?: emptyMap() + } + + val fragments: Map by lazy { + myUri.rawFragment?.ifBlank { null }?.let { keyValuePair -> + keyValuePair.split('&').associate { paramValue -> + val parts = paramValue.split("=", limit = 2) + if (parts.size == 2) { + parts[0] to URLDecoder.decode(parts[1], "UTF-8") + } else { + parts[0] to "" // Handle parameters without a value, e.g., "param&other=value" + } + } + } ?: emptyMap() + } + + actual fun scheme(): String? = myUri.scheme + + actual fun host(): String? = myUri.host + + actual fun port(): Int? { + // java.net.URI.getPort() returns -1 if the port is not set, so we handle that case. + val port = myUri.port + return if (port == -1) null else port + } + + actual fun path(): String? = myUri.path + + actual fun queryParameterNames(): Set = queryParameters.keys + + actual fun getQueryParameter(param: String): String? = queryParameters[param] + + actual fun fragments() = fragments +} diff --git a/quartz/src/jvmTest/java/com/vitorpamplona/quartz/TestResourceLoader.kt b/quartz/src/jvmTest/java/com/vitorpamplona/quartz/TestResourceLoader.kt new file mode 100644 index 0000000000..9a271521d6 --- /dev/null +++ b/quartz/src/jvmTest/java/com/vitorpamplona/quartz/TestResourceLoader.kt @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2025 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.quartz + +actual class TestResourceLoader { + actual fun loadString(file: String): String = + this@TestResourceLoader + .javaClass.classLoader!! + .getResourceAsStream(file) + .bufferedReader() + .use { it.readText() } +} diff --git a/quartz/src/jvmTest/resources/relayDB.txt b/quartz/src/jvmTest/resources/relayDB.txt new file mode 100644 index 0000000000..0977f44b3a --- /dev/null +++ b/quartz/src/jvmTest/resources/relayDB.txt @@ -0,0 +1,2539 @@ +wss://nostr.wine +wss://relay.orangepill.dev +wss://xmr.usenostr.org +wss://nostr.portemonero.com +wss://nostr.xmr.rocks +wss://relay.nostr.band +wss://filter.nostr.wine +wss://nostr.milou.lol +wss://nostr.mutinywallet.com +wss://nostr-pub.wellorder.net +wss://nostr.zebedee.cloud +wss://nos.lol +wss://brb.io +wss://bitcoiner.social +wss://nostr.decentony.com +wss://relay.nostriches.org +wss://paid.spore.ws +wss://eden.nostr.land +wss://puravida.nostr.land +wss://5dzvuefllevkhk7miqynaviguedxfnofrayu2xwfwtlkdg4radjdlyqd.onion +wss://relay-jp.nostr.wirednet.jp +wss://relay.nostrich.land +wss://nostr.holybea.com +wss://nostr-relay.nokotaro.com +wss://nostr-paid.h3z.jp +wss://nostrja-kari.heguro.com +wss://nostr.mom +wss://nostr.fediverse.jp +wss://nostr.h3z.jp +wss://universe.nostrich.land +wss://nostr.uselessshit.co +wss://atlas.nostr.land +wss://relay.snort.social +wss://universe.nostrich.landlangenlanges +wss://nostr.slothy.win +wss://nostr.plebchain.org +wss://nostr-relay.untethr.me +wss://relay.nostr.com.au +wss://nostr.inosta.cc +wss://relay.nostrati.com +wss://nostr.bitcoiner.social +wss://relay.nostrplebs.com +wss://relay.nostr.info +wss://nostr-relay.wlvs.space +wss://nostr.oxtr.dev +wss://nostr.onsats.org +wss://relay.wellorder.net +wss://relay.plebstr.com +wss://no.str.cr +wss://nostr.walletofsatoshi.com +wss://nostr.mwmdev.com +wss://relay.nostr.bg +wss://nostr.rocks +wss://nostr.fmt.wiz.biz +wss://nostr.orangepill.dev +wss://nostr-pub.semisol.dev +wss://nostr.sandwich.farm +wss://relay.nostr.ch +wss://relay.orange-crush.com +wss://private.red.gb.net +wss://nostr.lnprivate.network +wss://nostr.lu.ke +wss://relay.nostr.wirednet.jp +wss://lightningrelay.com +wss://relay.nostrgraph.net +wss://relay.nostrica.com +wss://relay.mostr.pub +wss://nostr-sg.com +wss://nostr.zkid.social +wss://relay.nostr.vet +wss://relay.nostr3.io +wss://relay.arsip.my.id +wss://relay.current.fyi +wss://global.relay.red +wss://nostr.island.network +wss://node01.nostress.cc +wss://relay.nostr.net.in +wss://relay.utxo.one +wss://relay-1.arsip.my.id +wss://nostrical.com +wss://nostro.cc +wss://rsslay.nostr.moe +wss://relay.nostr.or.jp +wss://nostream.unift.xyz +wss://blastr.f7z.xyz +wss://relay.honk.pw +wss://universe.nostrich.landlangja +wss://nostream.ocha.one +wss://paid-relay.nost.love +wss://offchain.pub +wss://nostr-usa.ka1gbeoa21bnm.us-west-2.cs.amazonlightsail.com +wss://nostr.terminus.money +wss://nostr.shawnyeager.net +wss://public.nostr.swissrouting.com +wss://nostrex.fly.dev +wss://relay.727whisky.com +wss://relay.cryptocculture.com +wss://relay.bleskop.com +wss://nostr.lorentz.is +wss://nostr.actn.io +wss://nostr-relay.lnmarkets.com +wss://nostr.openchain.fr +wss://relay.punkhub.me +wss://nostr.blipme.app +wss://nostr.swiss-enigma.ch +wss://nostr-verified.wellorder.net +wss://at.nostrworks.com +wss://21sats.net +wss://e.nos.lol +wss://nostr.mikedilger.com +wss://nostr.azte.co +wss://noster.bitcoiner.social +wss://relay.nostr.moe +wss://nostream.nostrly.io +wss://nostr.gives.africa +wss://nostr.21sats.net +wss://bitcoinmaximalists.online +wss://paid.nostrified.org +wss://nostr.1sat.org +wss://nostr.relayer.se +wss://sg.qemura.xyz +wss://nostr.coinos.io +wss://nostr.bitcoinplebs.de +wss://nostrich.friendship.tw +wss://nostr.sg +wss://eosla.com +wss://nostr.sidnlabs.nl +wss://nostr.foundrydigital.com +wss://relay.nostrview.com +wss://nostr.semisol.dev +wss://relay.f7z.io +wss://wlvs.space +wss://nostr.v0l.io +wss://nostr-relay.digitalmob.ro +wss://rsslay.fiatjaf.com +wss://relay.theorangepillapp.com +wss://relay.zeh.app +wss://nostr.zoomout.chat +wss://relay.stoner.com +wss://nostr.cercatrova.me +wss://relay.ryzizub.com +wss://nostr-1.nbo.angani.co +wss://nostr21.com +wss://spore.ws +wss://nostrue.com +wss://no-str.org +wss://relay.taxi +wss://ragnar-relay.com +wss://relay.austrich.net +wss://relay.nostr-latam.link +wss://1.noztr.com +wss://relay.nostr.scot +wss://test.relay.nostrich.day +wss://jiggytom.ddns.net +wss://nostr.bongbong.com +wss://relay.nostromo.social +wss://relay.sendstr.com +wss://nostr-dev.universalname.space +wss://relay.nostrcheck.me +wss://nostr.libertasprimordium.com +wss://nostr.kollider.xyz +wss://expensive-relay.fiatjaf.com +wss://nostr-sandbox.minds.io +wss://relay.nostrich.de +wss://nostr.gromeul.eu +wss://relay.nostr.wine +wss://nostr.screaminglife.io +wss://nostr-relay.derekross.me +wss://nostrica.nostrnotes.com +wss://paid.no.str.cr +wss://nostr.sethforprivacy.com +wss://nostr.dumpit.top +wss://nostr.herci.one +wss://cheery-paddock-rsakdrtc35c55n6yregn.wnext.app +wss://nostr.blockpower.capital +wss://nostr.nym.life +wss://nostr-verif.slothy.win +wss://fiatdenier.com +wss://nostr.bitcoin-21.org +wss://nostr.fluidtrack.in +wss://nostr.developer.li +wss://r.ayit.org +wss://relay.nostr.nu +wss://nostr.bostonbtc.com +wss://rly.social +wss://nostr.bridgey.dev +wss://relay.nostrprotocol.net +wss://nostr.mado.io +wss://nostr.einundzwanzig.space +wss://nostr2.actn.io +wss://nostr-relay.freedomnode.com +wss://nostr.pleb.network +wss://nostr.mouton.dev +wss://eelay.current.fyi +wss://nostr.notmyhostna.me +wss://nostr.pjv.me +wss://nostr.jatm.link +wss://nostr.fractalized.ovh +wss://nostr-relay.app.ikeji.ma +wss://relayer.ocha.one +wss://nostr.com.de +wss://nostr-2.afarazit.eu +wss://nostr.l00p.org +wss://nostr.drss.io +wss://relay.nostrify.io +wss://nostr.radixrat.com +wss://nostr-relay.bitcoin.ninja +wss://nostrsatva.net +wss://nostr.mustardnodes.com +wss://nostr01.vida.dev +wss://nostr.noones.com +wss://nostr.easify.de +wss://nostr3.actn.io +wss://moonbreeze.richardbondi.net +wss://nostr.naut.social +wss://private-nostr.v0l.io +wss://nostr.zaprite.io +wss://nostr.lightninglinks.xyz +wss://nostr.hackerman.pro +wss://nr.yay.so +wss://nostr.roundrockbitcoiners.com +wss://nostr.sovbit.host +wss://nostrelay.yeghro.site +wss://pow32.nostr.land +wss://nostr.1729.cloud +wss://nostr.rdfriedl.com +wss://nostr.h4x0r.host +wss://nostr.up.railway.app +wss://nostr.lnorb.com +wss://nostr.lordkno.ws +wss://relay.nostr.vision +wss://nostr-3.orba.ca +wss://satstacker.cloud +wss://freedom-relay.herokuapp.com +wss://nostr-relay.freeberty.net +wss://nostr.unknown.place +wss://nostr.delo.software +wss://relay.nostr.pro +wss://relay.minds.com +wss://nostr.ono.re +wss://relay.grunch.dev +wss://relay.cynsar.foundation +wss://relay.oldcity-bitcoiners.info +wss://relay.bitid.nz +wss://relay.nostr.xyz +wss://relay.futohq.com +wss://relay.farscapian.com +wss://astral.ninja +wss://relay.sovereign-stack.org +wss://nostr-2.zebedee.cloud +wss://nostr.nymsrelay.com +wss://relay.kronkltd.net +wss://relay.r3d.red +wss://universe.nostrich.landlangen +wss://nostr-dev.wellorder.net +wss://nostr.beta3.dev +wss://nostr.data.haus +wss://nostr.hugo.md +wss://relay-dev.cowdle.gg +wss://relay.dwadziesciajeden.pl +wss://tmp-relay.cesc.trade +wss://nostr.massmux.com +wss://relay.nostr.africa +wss://nostr1.tunnelsats.com +wss://nostr.f44.dev +wss://relay.n057r.club +wss://nostr-verif.slothy.com +wss://nostr.1f52b.xyz +wss://nostr.sebastix.dev +wss://nostr.lightning.contact +wss://nostr.rly.social +wss://noster.online +wss://relay.lexingtonbitcoin.org +wss://nostr.bitcoinbay.engineering +wss://nostr.howtobitcoin.shop +wss://blg.nostr.sx +wss://deschooling.us +wss://foolay.nostr.moe +wss://freespeech.casa +wss://nostr-01.bolt.observer +wss://nostr-01.dorafactory.org +wss://nostr-au.coinfundit.com +wss://nostr-eu.coinfundit.com +wss://nostr-relay.alekberg.net +wss://nostr-pub1.southflorida.ninja +wss://nostr-relay.gkbrk.com +wss://nostr-relay.pcdkd.fyi +wss://nostr-relay.schnitzel.world +wss://nostr-us.coinfundit.com +wss://nostr.21crypto.ch +wss://nostr.600.wtf +wss://nostr.8e23.net +wss://nostr.app.runonflux.io +wss://nostr.arguflow.gg +wss://nostr.bch.ninja +wss://nostr.chainofimmortals.net +wss://nostr.cizmar.net +wss://nostr.cheeserobot.org +wss://nostr.coollamer.com +wss://nostr.corebreach.com +wss://nostr.cro.social +wss://nostr.easydns.ca +wss://nostr.globals.fans +wss://nostr.handyjunky.com +wss://nostr.itas.li +wss://nostr.sectiontwo.org +wss://nostr.spleenrider.one +wss://nostr.thibautrey.fr +wss://nostr.uthark.com +wss://nostr.vulpem.com +wss://nostr.w3ird.tech +wss://nostr.whoop.ph +wss://nostr.yuv.al +wss://nostr01.opencult.com +wss://nostre.cc +wss://nostream.denizenid.com +wss://nostring.deno.dev +wss://pow.nostrati.com +wss://relay-pub.deschooling.us +wss://nostr.jiashanlu.synology.me +wss://nostr.klabo.blog +wss://relay.valireum.net +wss://nostr.fly.dev +wss://nostr.nordlysln.net +wss://nostr.zerofeerouting.com +wss://rsslay.nostr.net +wss://nostr-relay.nonce.academy +wss://nostr.rewardsbunny.com +wss://lv01.tater.ninja +wss://nostr-2.orba.ca +wss://nostr.orba.ca +wss://nostr.supremestack.xyz +wss://nostrrelay.com +wss://relay.nostr.au +wss://nostr.oooxxx.ml +wss://nostr.yael.at +wss://nostr-relay.trustbtc.org +wss://nostr.namek.link +wss://nostr-relay.wolfandcrow.tech +wss://nostr.satsophone.tk +wss://relay.dev.kronkltd.net +wss://nostr2.namek.link +wss://relay.21spirits.io +wss://relay.minds.io +wss://nostr.d11n.net +wss://nostr.tunnelsats.com +wss://nostr.leximaster.com +wss://mule.platanito.org +wss://nostr.robotechy.com +wss://relay.nostrmoto.xyz +wss://relay.boring.surf +wss://nostr.gruntwerk.org +wss://nostr.hyperlingo.com +wss://nostr.ethtozero.fr +wss://nostr.nodeofsven.com +wss://nostr.jimc.me +wss://nostr.utxo.lol +wss://relay.nyx.ma +wss://nostr.shmueli.org +wss://wizards.wormrobot.org +wss://nostr.sovbit.com +wss://nostr.datamagik.com +wss://relay.nostrid.com +wss://nostr1.starbackr.me +wss://relay.nostr.express +wss://nostr.formigator.eu +wss://nostr.xpersona.net +wss://nostr.digitalreformation.info +wss://nostr-relay.usebitcoin.space +wss://nostr-alpha.gruntwerk.org +wss://nostr-relay.australiaeast.cloudapp.azure.com +wss://nostr-relay.smoove.net +wss://nostr-relay.j3s7m4n.com +wss://nostr.demovement.net +wss://nostr.thesimplekid.com +wss://nostr.aozing.com +wss://nostr.blocs.fr +wss://no.str.watch +wss://btc.klendazu.com +wss://nostr.mrbits.it +wss://nostr.zenon.wtf +wss://no.contry.xyz +wss://nostream.gromeul.eu +wss://relay.nostr.ro +wss://nostr.ncsa.illinois.edu +wss://nostr.itssilvestre.com +wss://nostr.chaker.net +wss://knostr.neutrine.com +wss://nostr.pobblelabs.org +wss://nostr.simatime.com +wss://relay.nosphr.com +wss://student.chadpolytechnic.com +wss://nostr.localhost.re +wss://nostr.coinsamba.com.br +wss://deconomy-netser.ddns.net:2121 +wss://nostr.21m.fr +wss://zur.nostr.sx +wss://nostr-relay.texashedge.xyz +wss://spleenrider.herokuapp.com +wss://nostr.bitcoin.sex +wss://relay.nostrzoo.com +wss://nostr.blockchaincaffe.it +wss://nostr-bg01.ciph.rs +wss://knostr.neutrine.com:8880 +wss://nostr.ahaspharos.de +wss://nostr.argdx.net +wss://nostr.snblago.com +wss://merrcurr.up.railway.app +wss://nostr.bingtech.tk +wss://relay.nostr.wf +wss://relay.koreus.social +wss://nostr.randomdevelopment.biz +wss://relay.nostr.hu +wss://relay.nostr.lu +wss://relay.nostr.ae +wss://middling.myddns.me:8080 +wss://nostr.nikolaj.online +wss://relay.nostrology.org +wss://nostr.satoshi.fun +wss://nostream.kinchie.snowinning.com +wss://nostr.lapalomilla.mx +wss://relay.thes.ai +wss://rsr.uyky.net:30443 +wss://nostrafrica.pcdkd.fyi +wss://nostr.bitcoin-basel.ch +wss://relay.21baiwan.com +wss://nostr.ddns.net:8008 +wss://free-relay.nostrich.land +wss://nostr.lukeacl.com +wss://nostr.ddns.net +wss://nostr.rocket-tech.net +wss://nostr-1.afarazit.eu +wss://nostr.0nyx.eu +wss://nostr-mv.ashiroid.com +wss://lbrygen.xyz +wss://nostr.community.networks.deavmi.assigned.network +wss://nostr.ownscale.org +wss://relay1.gems.xyz +wss://nostr.soscary.net +wss://nostr.0xtr.dev +wss://damus.io +wss://relay.alien.blue +wss://nostr.btcmp.com +wss://relayer.fiatjaf.com +wss://relay.lacosanostr.com +wss://adult.18plus.social +wss://nostrrr.bublina.eu.org +wss://relay.stoner +wss://nostr.pwnshop.cloud +wss://nostr.directory +wss://nostr-relay-dev.wlvs.space +wss://member.cash +wss://relay.nyc1.vinux.app +wss://nostr-relay.digitamob.ro +wss://nor.st +wss://nostr.topeth.info +wss://nostr.rocketstyle.com.au +wss://relay.tnano.duckdns.org +wss://nostr.21l.st +wss://electra.nostr.land +wss://relay.codl.co +wss://nostr.koning-degraaf.nl +wss://relay.mrjohnsson.net +wss://nostr.thank.eu +wss://relay.stonez.me +wss://relay.nostr.distrl.net +wss://relay.valera.co +wss://api.semisol.dev +wss://nostr.lol +wss://relay.shitforce.one +wss://n-word.sharivegas.com +wss://lamp.wtf +wss://nostr.bitcoinpuertori.co +wss://nostr-01.bolt.oberver +wss://3d515c5277e9.ngrok.io +wss://nostr.xmrk.mooo.com +wss://alphapanda.pro +wss://relays.world +wss://universe.nostrich.landlangzh +wss://arnostr.permadao.io +wss://relay.chenxixian.cn +wss://universe.nostrich.landlangzhlangen +wss://v2r.chenxixian.cn +wss://nostr-relay-test.nokotaro.work +wss://universe.nostrich.landlangjalangen +wss://nostr.risa.zone +wss://relay.nosbin.com +wss://translate.argosopentech.com +wss://edennostr.land +wss://nostr.kawagarbo.xyz +wss://nostr.member.cash +wss://ch1.duno.com +wss://nostream-production-b80e.up.railway.app +wss://relay1.nostrich.cloud +wss://relay.t5y.ca +wss://nostr.zhongwen.world +wss://nostr.p2sh.co +wss://nostr.thomascdnns.com +wss://nostream.simon.snowinning.com +wss://relay.nostr.blockhenge.com +wss://nostr.buythisdip.com +wss://nostrua.com +wss://relay.bigred.social +wss://lingoh.dev +wss://nostr.poster.place +wss://nostr.geekgalaxy.com +wss://oarnx6xdrq5mygfdrbmzsvh3is3holefpz2x4qwbopwcicwd63gcivid.onion +wss://relay.nostropolis.xyz +wss://nostream-production-ba43.up.railway.app +wss://nostr.sabross.xyz +wss://relay.nvote.co +wss://nostrati.com +wss://cloudnull.land +wss://nostr.frennet.xyz +wss://nostr.wine.com +wss://nostr.sactiontwo.org +wss://nostr.liberty.fans +wss://nostr.primz.org +wss://btc-italia.online +wss://homenode.local:4848 +wss://nostr.frennet.xyzl +wss://relay.roosoft.com +wss://rasca.asnubes.art +wss://nostr.bitcoin.sexanewlycre +wss://nostr.barf.bz +wss://nostr.middling.mydns.jp +wss://relay.xuzmail.com +wss://no-str.wnhefei.cn:28443 +wss://quirky-bunch-isubghsvoi26fbbt3n7o.wnext.app +wss://nostr.fennel.org:7000 +wss://nostr.0ne.day +wss://nostr.vpn1.codingmerc.com +wss://nostr.jacany.com +wss://nostream.lucas.snowinning.com +wss://relay.beta.fogtype.com +wss://nostr.zue.news +wss://nostream.madbean.snowinning.com +wss://nostr2.rbel.co +wss://relay.1bps.io +wss://nostream-relay-nostr.831.pp.ua +wss://zee-relay.fly.dev +wss://nostrrelay.geforcy.com +wss://relay.nostr.jhot.me +wss://nostr.itredneck.com +wss://nostr.h3y6e.com +wss://relay.bitcoiner.social +wss://hos.lol +wss://iris.to +wss://nostr-pub.senisol.dev +wss://nostr-pub.wellirder.net +wss://bitcoinforthe.lol +wss://relav.nostr.info +wss://3e32-200-229-144-129.ngrok.io +wss://nostr-relay.hzrd149.com +wss://nostr-world.h3z.jp +wss://nostr.thesamecat.io +wss://nostr.compile-error.net +wss://relayable.org +wss://mostra.milou.lol +wss://nproxy.cc +wss://nostr.bitmatk.io +wss://coracle.social +wss://umbrel.local:4848 +wss://nostr.ownbtc.online +wss://wss.nostrgram.co:444 +wss://nostr.minimue81.selfhost.co +wss://relay.current.fy +wss://nostream.nostr.parts +wss://nostr.zebede.cloud +wss://nostrwhoop.ph +wss://relay.nostrified.org +wss://nproxy.zerologin.co +wss://nostr.pcdkd.fyi +wss://relay.kongerik.et +wss://nostr.eden.land +wss://nostr.retroware.run.place +wss://relay.humanumest.social +wss://bhagos.org +wss://hushvault.ie +wss://nostream-production-9458.up.railway.app +wss://nostr.nakamotosatoshi.cf +wss://globals.fans +wss://nostr.cruncher.com +wss://nostr.global.fan +wss://relay.nostr.snblago.com +wss://nostr.nokotaro.com +wss://ostr-1.afarazit.eu +wss://relay.zhix.in +wss://stats.nostr.band +wss://nostr.fine +wss://vxlw4rlg7go34ol43g4gxbvfu4txdzjauquvnbptzwjflezs3vik55id.onion +wss://big.fist.black +wss://universe.nostrich.landlangzhlangja +wss://relay.plebz.space +wss://nostrich.land +wss://relay.mynostr.fun +wss://swiss-enigma.ch +wss://nostr1.current.fyi +wss://relay.atlas.nostr.land +wss://nostr.band +wss://n.wingu.se +wss://nostr.jmdtx.com +wss://nostrproxy-1.f7z.io +wss://nostr.ch +wss://roundrockbitcoiners.com +wss://nostr.sept.ml +wss://srelay.roli.social +wss://nostr.monostr.com +wss://nostr.dojotunnel.online +wss://nostrica.dojotunnel.online +wss://nostr.shadownode.org +wss://thes.ai +wss://rsslay.wss +wss://nostr.vol.io +wss://nostrgram.co +wss://habla.news +wss://runningnostr.lol +wss://mostr.pub +wss://relay.example2.com +wss://profiles.f7z.io +wss://nostr.adpo.co +wss://jp-relay-nostr.invr.chat +wss://nostr.anchel.nl +wss://mutinywallet.com +wss://relay.nostrbr.online +wss://filter.eden.nostr.land +wss://relay.nostrdocs.com +wss://relay.nostr.lucentlabs.co +wss://n.xmr.se +wss://nostr.relayer.rs +wss://monad.jb55.com:8080 +wss://nostr.watch +wss://universe.nostrich.landlangenlangzhlangja +wss://nostr.asdf.mx +wss://ts.relays.world +wss://arc1.arcadelabs.co +wss://stealth.wine +wss://nostr.bg +wss://really.nostr.bg +wss://realy.nostr.bg +wss://relai.nostr.bg +wss://relay-verified.deschooling.us +wss://4.up.railway.app +wss://nostr-relay.aapi.me +wss://nostr-z9tc.onrender.com +wss://nostrich.site +wss://nostr.ginuerzh.xyz +wss://310b-200-229-144-129.ngrok.io +wss://nostr.aste.co +wss://black.nostrcity.club +wss://nostr.guru +wss://nostrica.com +wss://relay.leesalminen.com +wss://nostr.shroomslab.net +wss://meta-relay-beta.nostr.wirednet.jp +wss://nostr.reamde.dev +wss://nostr.africa +wss://powrelay.xyz +wss://rsslay.data.haus +wss://nostr.danvergara.com +wss://nostr.one.re +wss://dev2.hazilitt.fiatjaf.com +wss://nostr-2.zebdeee.cloud +wss://zerosequioso.com +wss://brb.io.relay +wss://relay.realsearch.cc +wss://nodestr.fmt.wiz.biz +wss://r.alphaama.com +wss://nostr.relay-wlvs.space +wss://relay.21spiritis.io +wss://nostr.pinkanki.org +wss://nostr.damus.io +wss://fin-nostr.seekdisruption.com +wss://relay.nostr.lu.ke +wss://nostr.rdfried.com +wss://nostr.trustbtc.org +wss://nostr.verymad.net +wss://relay.damus.info +wss://relays.nostrplebs.com +wss://nostr.688.org +wss://15171031.688.org +wss://dgi4mb7antpcmrx4rynm6xq52xzt5duvxa4iwucq4mszgpz6smrjajqd.onion +wss://mastodon.cloud +wss://nostr.ch3n2k.com +wss://nostr.forecastdao.com +wss://nostr.nostrelay.org +wss://nostr.robotesc.ro +wss://nostr.test.aesyc.io +wss://nostr.web3infra.xyz +wss://nostrrelay.maciejz.net +wss://nostrsxz4lbwe-nostr.functions.fnc.fr-par.scw.cloud +wss://nostrpurple.com +wss://rsslay.ch3n2k.com +wss://nos.qghs.in +wss://nostr.nordlysln.net:3241 +wss://nostr.net.in +wss://relay.rip +wss://universe.nostrich.landlangenlangja +wss://wmv-vm.local:4848 +wss://relay.austritch.net +wss://relay.oxtr.dev +wss://rwlay.bigred.social +wss://relay.lexongtonbitcoin.org +wss://knostr.neutrine +wss://nostr.online +wss://filter.stealth.wine +wss://nostream-production-5895.up.railway.app +wss://nostr.stereosteve.com +wss://relay01.apus.network +wss://test.nostr.0x50.tech +wss://nostr.0x50.tech +wss://nostr.256k1.dev +wss://nostr.malin.onl +wss://jqiwgflfw4dezjsy42frompmknrlcfazoiyngftgknj7yrmnhtobd7id.local +wss://b.ayit.org +wss://nostrelay.rajabi.ca +wss://off20chain.pub +wss://nostr.milou.land +wss://nostr.primedomain.fr +wss://nostr.theblockreward.com +wss://anon.computer +wss://relay.hamnet.io +wss://nostramsterdam.vpx.moe +wss://global-relay.cesc.trade +wss://btcpay.kukks.org +wss://relay.cent2sat.com +wss://nostr.mnethome.de +wss://nostream.sh4.red +wss://klockenga.social +wss://nostream.megadope.snowinning.com +wss://nostr.cvilleblockchain.org +wss://nostr.bitocial.xyz +wss://nostr.bitcoiner.socail +wss://nostr-relay.eniehack.net +wss://greenart7c3.dedyn.io +wss://nostr.data.naus +wss://8.tcp.ngrok.io:19607 +wss://relay.nostr24.com +wss://d463rbo7dgbfuxvvxpory2og2etl4gttfzmqcixdq7rpts47lpgolkyd.onion +wss://dublin.saoirse.dev +wss://www.weixin.com +wss://nostr-rs-relay.cryptoassetssubledger.com +wss://nostr.kojira.net +wss://nostr.fan +wss://nostr.pk +wss://getalpy.com +wss://billert.xyz +wss://circle-ay.info +wss://jawsh.xyz +wss://walletofsatoshi.com +wss://ogblock.xyz +wss://nodestrich.com +wss://kunigaku.gith +wss://nostr.21ideas.org +wss://133332.xyz +wss://asats.io +wss://nostrchack.me +wss://chalow.net +wss://cashu.me +wss://tsukemonogit.git +wss://h3y6e.com +wss://elder.nostr.land +wss://xmr.rocks +wss://nostr.build +wss://mofumemo.com +wss://kpherox.dev +wss://sb.nostr.band +wss://tyiu.xyz +wss://welkinhere.githu +wss://ocha.one +wss://in.tips +wss://vitorpamplona.co +wss://fiatjaf.com +wss://akiomik.github.io +wss://stacker.news +wss://nvk.org +wss://lordkno.ws +wss://nostr.indus +wss://lotdkno.ws +wss://nosutora.com +wss://milou.lol +wss://mostr.pu +wss://dergigi.com +wss://shirehodl.com +wss://cash.app +wss://h3z.jp +wss://murachue.cytes.net +wss://snowcait.gith +wss://jb55.com +wss://nodeless.io +wss://orange-crush.com +wss://nostr.com.au +wss://oooxxx.ml +wss://plebs.place +wss://ahr999.com +wss://penpenpng.github.io +wss://nostrpurple.co +wss://thank.eu +wss://weep.jp +wss://tigerville.no +wss://nostrcheck.me +wss://frenstr.com +wss://ln.tips +wss://ryumu.dev +wss://honeyroad.store +wss://harlembitcoin.com +wss://f7z.io +wss://relay.fan +wss://nisshiee.org +wss://www.lopp.net +wss://getalby.com +wss://heguro.com +wss://wil.bio +wss://b.tc +wss://nodedttich.com +wss://relay.taldra.in +wss://relat.nostrica.com +wss://nostr.boring.surf +wss://nostr.raitisoja.net +wss://nostr.astrox.app +wss://nostr.mjex.me +wss://slick.mjex.me +wss://nostr.hrmb.org +wss://relay.semaphore.life +wss://rss.nostr.band +wss://63ragcfwb5xhoe5gfflazfyrde3qjdo73cblhhmnbviizowdo2q5haid.onion:5051 +wss://nostrblip.app +wss://relay.vanderwarker.family +wss://relay-local.cowdle.gg +wss://relay.damus.com +wss://relay.reeve.cn +wss://relay.strfry.net +wss://relay.alxgsv.com +wss://nostrv0l.io +wss://relay.nostrula.com +wss://release.nostr.band +wss://nostr.k3tan.com +wss://nostr.bitcoin.social +wss://thesimplekid.space +wss://relay.ypcloud.com +wss://at.nostrwork.at +wss://nostream.dev.kronkltd.net +wss://nostr-relay.xbytez.io +wss://relay.nostr.io +wss://relay.nvote.co:443 +wss://relay.cryptoculture.com +wss://rjj6ejkihilniytxs56qrgtttgcfnnjvbii6vaas6jzppcmekd63ugad.local +wss://puravida.nostr.land.com +wss://bitcoinmaximalist.online +wss://wine.nostr +wss://nostr.messagepush.io +wss://nostrich.love +wss://relaynostrplebs.com +wss://hamstr.to +wss://yosupp.app +wss://snort.social +wss://relay.nostr.gt +wss://nost.ratchat.nl +wss://nostr.chrissmith.site +wss://i.relay.boats +wss://nostr.wineto +wss://nostr.eluc.ch +wss://nostrplebs.com +wss://nostr.tools.global.id +wss://nostr.rocketnode.space +wss://relay.roli.social +wss://bitcoin.nostr.com +wss://relay.badgr.space +wss://nostriches.club +wss://nostr-check.me +wss://nostrelay.nokotaro.com +wss://rbr.bio +wss://rly.bopln.com +wss://6amyhf3sjvgxe5qzbx4xn52pcnqresdmi7szxurp6umkvz6mthxjdcad.onion +wss://6amyhf3sjvgxe5qzbx4xn52pcnqresdmi7szxurp6umkvz6mthxjdcad.local +wss://20nos.lol +wss://test.theglobalpersian.com +wss://nostr.exposed +wss://nostr-pub.liujiale.me +wss://nostream.frank.snowinning.com +wss://nstrs.fly.dev +wss://eospark.com +wss://relay.nosterplebs.com +wss://nproxy.kristapsk.lv +wss://nostr.universalname.space +wss://relays.snort.social +wss://nostr.how +wss://kukks.org +wss://nostr.dutch.cryptonews +wss://relay.cryptojournaal.net +wss://relay.dutch.cryptonews +wss://nostr.cryptojournaal.net +wss://no-str.wnhefei.cn +wss://www.131.me +wss://rsr.uyky.net +wss://nostr-relay.ie9.org +wss://nostr.fmt.wis.biz +wss://nostr.exotr.dev +wss://nostr.merrcurr.com +wss://realy.damus.io +wss://nerostr.xmr.rocks +wss://rkdgwzgvcgrciemlnfsxqgyrv5whgpw44s6zycokmuchpq4ucflgjtqd.local +wss://nostr.simplex.icu +wss://ralay.damus.io +wss://relay.kronkitd.net +wss://nostr.info +wss://nostr.lnnodeinsight.com +wss://nostr.truckenbucks.com +wss://brt.io +wss://nostr.lingoh.dev +wss://relay.nor.st +wss://nostr-relay.inmarkets.com +wss://wiz.biz +wss://nostream.git +wss://nostr.dpbu.de +wss://wcl2meyp236fa3dmfzfyq6aacbdoixrlocb6zozjs6xklxizschj2did.local +wss://relay.nostr.co.jp +wss://relap.orzv.workers.dev +wss://nostr.bitcoiner.socia +wss://eden.nosrt.land +wss://strfry.cryptocartel.social +wss://nostr.citizenry.technology +wss://universe.nostrich.landlang +wss://nostr.inprivate.network +wss://relay.snort.test +wss://lpkue6jtz3pnp7zok4jwlct4n3mzuffsfrpagiffsuplyaswhdtmpoid.local +wss://nostr.rezhajulio.id +wss://lnbits.eldamar.icu +wss://nostr.freefrom.fi +wss://yael.at +wss://rain8128.github.io +wss://badges.page +wss://latam1-nostr.stealthy.co +wss://nostr.relay.se +wss://nfdn.testnet.dotalgo.io +wss://relav.nostr3.io +wss://ofchain.pub +wss://nostr.fmt.wiz.bi +wss://relay.gui.dog +wss://eden.nostry.land +wss://nostr.relay.limo +wss://relay.nostrichs.org +wss://20nostr.mom +wss://relay20damus.io +wss://nostr.sandwich.pro +wss://sq.qemura.xyz +wss://nostr-pub.seminol.dev +wss://nostr.eunundzwanzig.space +wss://nostr.bitcoinet.social +wss://nostr-relay.untether.me +wss://relay.nostr.pub +wss://nostr.100p.org +wss://7tdom3xuus7ekv423ul46w3j43zyixjj54yoe62bndpcrgii3adeppid.local +wss://nostr.gram +wss://nostr.videre.net +wss://nostr-2.zebedee.cloudwss +wss://nostr-pub.wellorder.netwss +wss://sonzai.net +wss://snort.fail +wss://ppavybjpqjft5slnpeovehbegomhwtvvxtesvwwdrfndz6qe2c5kf2ad.local +wss://nostr.land +wss://relay.nvote.com +wss://purevida.nostr.land +wss://nostr.bitcoiner.soical +wss://nostr.inosta.co +wss://nas.lol +wss://wss.nostr.milou +wss://nostr.cheesebot.org +wss://eyeswideshut.ath.cx +wss://test.relays.world +wss://relay.snort.com +wss://relay.nostrplebs.co +wss://nostr.kimi.im +wss://nostrum.com +wss://wss.nostr.wine +wss://relay.usenostr.org +wss://paladium.my:4848 +wss://umbrel.home.local:4848 +wss://nostr.metamadeenah.com +wss://lnbits.sdbtc.org +wss://relay.nostr.mutinywallet.com +wss://relay.theglobalpersian.com +wss://relay1.easymeta.app +wss://relay.nostris.online +wss://s1.wonder3.org +wss://eden.nostraland +wss://byc.klendazu.com +wss://ephemerelay.mostr.pub +wss://7si6co27cvaw5yjyx6asvxfmaw5ah2arywwgrem4y5svi5ntskoeb5id.onion +wss://nwmdev.com +wss://nostro.online +wss://nostr.massimux.com +wss://nostr.glate.ch +wss://nostr.openordex.org +wss://nostr.schorsch.fans +wss://nostr-relay-dev.nisshiee.org +wss://ibz.me +wss://alexandernostrplebs.com +wss://fishbanananostrplebs.com +wss://relay.nostrcheck.com +wss://nostr.roli.io +wss://nostr.net.za +wss://nostr.worldkey.io +wss://nostr-pub.welloorder.net +wss://nostr.actin.io +wss://nostrzebedee.cloud +wss://nostr.zclub.app +wss://nostr.13x.sh +wss://nostr.totient.xyz +wss://nostr1.federated.computer +wss://nostr.zhix.in +wss://nostr.vdstruis.com +wss://caro-relay.fiatjaf.com +wss://nostr.winewss +wss://notstro.wine +wss://nostr.btc-library.com +wss://nostr.phenomenon.space +wss://nostr.octr.dev +wss://nostr.impervious.live +wss://nostr.plebs.space +wss://iefan.tech +wss://w3ird.tech +wss://yunginter.net +wss://nostr.coach +wss://sleepy.cafe +wss://freespeechextremist.com +wss://nostr.uselessshit.com +wss://liberdon.com +wss://eveningzoo.club +wss://gleasonator.com +wss://mindly.social +wss://ottawa.place +wss://noagendasocial.com +wss://poa.st +wss://misskey.io +wss://misskey.cf +wss://nostr.bybieyang.com +wss://mastodon.online +wss://toad.social +wss://best-friends.chat +wss://universeodon.com +wss://mastodon.world +wss://mastodon.social +wss://nostr.vulpem +wss://nicecrew.digital +wss://front-end.social +wss://nostr-relay.wellorder.net +wss://relays.pro +wss://rsslay.sovbit.host +wss://seal.cafe +wss://social.6bq.de +wss://universe.nostrich.landlangjalangzh +wss://social.xenofem.me +wss://mi.hibi-tsumo.com +wss://mstdn.social +wss://mas.to +wss://relay.rebelbase.site +wss://pixelfed.social +wss://digitalcourage.social +wss://ruby.social +wss://cr8r.gg +wss://nijimiss.moe +wss://returtle.com +wss://lor.sh +wss://toot.community +wss://mstdn.jp +wss://relay.berserker.town +wss://nostr.rajabi.ca +wss://fosstodon.org +wss://misskey.takehi.to +wss://izj3isbk3pmade74ontdijodhehsytnw2iokdhh6k3flk4mq2pau6sid.onion +wss://mastodon.scot +wss://nostriches.org +wss://aus.social +wss://relay.nostr.amane.moe +wss://romancelandia.club +wss://stonez.me +wss://merrcurr.com +wss://nostr.ist +wss://onprem.wtf +wss://fedibird.com +wss://s2.wonder3.org +wss://freespech.casa +wss://disabled.social +wss://relay.house +wss://nostr-pub.welllorder.net +wss://social.teamb.space +wss://infosec.exchange +wss://blockedur.mom +wss://progressivecafe.social +wss://mstdn.ca +wss://c.im +wss://mefi.social +wss://basebitcoinplebs.place +wss://med-mastodon.com +wss://ohai.social +wss://defcon.social +wss://pxlmo.com +wss://zlocur7ctbds4qsdswb3qpkp6n2e2ywqne2fp2tdn4fqubpudfiyxwid.local +wss://thebag.social +wss://mstdn.party +wss://relay.serpae.xyz +wss://clew.lol +wss://qoto.org +wss://relay.exchange +wss://nostr.relayable.org +wss://mastodon.coffee +wss://kmy.blue +wss://home.social +wss://detmi.social +wss://brighteon.social +wss://nostr.nom +wss://theblower.au +wss://astral.nostr.land +wss://beige.party +wss://orangepill.dev +wss://redgreenblue.click +wss://nostr.fredix.xyz +wss://nostr.essydns.ca +wss://nostr.private.network +wss://nostr.member.cas +wss://nostr-rely.digitalmob.ro +wss://relay.nostr +wss://relay.current +wss://no-str.or +wss://pl.gamers.exposed +wss://studentchadpolytechnic.com +wss://scicomm.xyz +wss://relay.alien-sos.gov +wss://masto.es +wss://spinster.xyz +wss://parallels-parallels-virtual-platform.local:4848 +wss://relay.daums.io +wss://kolektiva.social +wss://mastodonapp.uk +wss://convo.casa +wss://sfba.social +wss://techhub.social +wss://leafposter.club +wss://nrw.social +wss://mastodon.uno +wss://handon.club +wss://social.vivaldi.net +wss://nostr.goller.net +wss://minazukey.uk +wss://mstdn.beer +wss://expressional.social +wss://paid.nostr.0x50.tech +wss://mstdn.nere9.help +wss://relay.nostr.ai +wss://relay.noswss +wss://relay.nwss +wss://furry.engineer +wss://uselessshit.co +wss://kosmos.social +wss://mynostr.io +wss://premis.one +wss://social.tchncs.de +wss://retro.pizza +wss://pearl-mount-showed-fishing.trycloudflare.com +wss://kpa4k6acxzjv2m2p72keftbpaymwpq2h67jqnin3d4y3djxyheuifoqd.onion +wss://gm7.social +wss://relays.nostr.info +wss://chitter.xyz +wss://hackers.town +wss://anarchism.space +wss://relay.nostrica +wss://halifaxsocial.ca +wss://asimon.org +wss://nostr.blipme.add +wss://troet.cafe +wss://octodon.social +wss://m.cmx.im +wss://filename-ambassador-distance-mountains.trycloudflare.com +wss://nostr.getgle.org +wss://relay.froth.zone +wss://novoa.nagoya +wss://relay.dispute.systems +wss://clubcyberia.co +wss://thechimp.zone +wss://coolsite.win +wss://puravida.nostra.land +wss://shelter.local:1111 +wss://det.social +wss://nostr-2.zebee.cloud +wss://chaosfem.tw +wss://nostr.v01.io +wss://social.kechpaja.com +wss://mastodon.green +wss://plebchain.nostr +wss://plebchain.nostr.land +wss://relay.onsats.org +wss://u5epuanp2fbie4phw6zekzna6zotvsffji4td4ee7iwgwdxlz4kwqqad.onion:5051 +wss://3ddc8bbee6db.ngrok.app +wss://b4968f09859e.ngrok.io +wss://genserver.social +wss://masto.ai +wss://hachyderm.io +wss://shitpost.cloud +wss://oldbytes.space +wss://mastodon.ie +wss://baraag.net +wss://nostr.dvdt.dev +wss://relay.com.de +wss://nostr.rbel.co +wss://bologna.one +wss://nostr-relay.app +wss://kagamisskey.com +wss://nostr-rs-relay.phamthanh.me +wss://nostr.bcmp.com +wss://blogstack.io +wss://rly.nostrkid.com +wss://mastodon.bida.im +wss://freeatlantis.com +wss://pieville.net +wss://climatejustice.rocks +wss://relay.mynostr.id +wss://relay.farscapian +wss://relay.blogstack.io +wss://orwell.fun +wss://misskey.04.si +wss://sushi.ski +wss://nostr.milou.lo +wss://pawoo.net +wss://tooter.social +wss://mastodon.sdf.org +wss://nostr.com +wss://misskey.design +wss://macaw.social +wss://relay.nostr.inforelay.nostr.band +wss://pub1.southflorida.ninja +wss://strawberry-pudding.net +wss://mastodon-japan.net +wss://nostream.0x50.tech +wss://multiplextr.coracle.social +wss://pleroma.skyshanty.xyz +wss://uxxq6b2enojvflhkrzsg4erakd5rrb7v2cql4m4pspj4xtqwyli47rid.local +wss://masto.deoan.org +wss://replay.damus.io +wss://melhorque.com.br +wss://nostr1.actn.io +wss://nostr.bolt.fun +wss://relay.vtbmoyu.com +wss://eosla.comrelay.zeh.app +wss://bikeshed.party +wss://nostr.xanny.family +wss://milker.cafe +wss://nostr.give.africa +wss://relay.got-relayed.com +wss://cum.salon +wss://puravid.nostr.land +wss://soc.punktrash.club +wss://seafoam.space +wss://h4.io +wss://nostr.swiss.enigma.ch +wss://toot.cafe +wss://sneed.social +wss://newsie.social +wss://indg.club +wss://xoxo.zone +wss://relay.nostr.bitcoiner.social +wss://relay.snort.band +wss://socel.net +wss://social.coop +wss://postpandemicparty.org +wss://merveilles.town +wss://search.nostr.wine +wss://search.nos.today +wss://mstdn-huahin.com +wss://eden.nostr.la +wss://nostrja-kari-nip50.heguro.com +wss://relay.gems.xyz +wss://plnetwork.xyz +wss://nostr.swiss-enigma.sh +wss://geofront.rocks +wss://toot.io +wss://indieweb.social +wss://mastodon.content.town +wss://awaymessage.club +wss://relay.intify.io +wss://mstdn.science +wss://maniakey.com +wss://otadon.com +wss://mstdn.guru +wss://misskey.noellabo.jp +wss://hessen.social +wss://mastodon.top +wss://ipv6.nostr.wirednet.jp +wss://relay.nostr-relay.org +wss://cum.camp +wss://nebbia.fail +wss://current.fyi +wss://bae.st +wss://lolison.network +wss://ioc.exchange +wss://bylines.social +wss://decayable.ink +wss://nostr.unitedserializer.com +wss://urbanists.social +wss://dark-elves.social +wss://writing.exchange +wss://nostr.rikmeijer.nl +wss://misskey.social +wss://ht.nixre.net +wss://mathstodon.xyz +wss://t7jvqwu35hneszx7fihsprbcpwonlcfnsjr4xtn6shqgwbv324w4gdid.local +wss://abla.news +wss://muenchen.social +wss://homeserver.drake-carp.ts.net:4848 +wss://snailedit.social +wss://mastodon.gamedev.place +wss://tech.lgbt +wss://mast.lat +wss://econtwitter.net +wss://veganism.social +wss://btclolap6mm4tl37huslk6j76enq7qxaj2kwq7w6cdr5ros56eletcqd.onion +wss://toot.cat +wss://nostr.zenon.info +wss://misskey.art +wss://nostr.hushvault.ie:4848 +wss://o6ga6lxnax2z7pgkkenifollohkrv55r36mdzdtofi7d5yyif2f4o5yd.onion:5051 +wss://20nostr-pub.wellorder.net +wss://ecoevo.social +wss://nostr.zerofiat.world +wss://nostr.atitlan.io +wss://detroitriotcity.com +wss://rollenspiel.social +wss://paquita.masto.host +wss://literatur.social +wss://dave.st.germa.in +wss://sunny.garden +wss://nostrpro.xyz +wss://relay.getalby.com +wss://misskey.systems +wss://mamot.fr +wss://social.anoxinon.de +wss://relay.nostr.social +wss://mindmachine.org +wss://microblog.club +wss://relay.utxo.com +wss://universe.nostrich.landlangth +wss://social.teci.world +wss://social.freetalklive.com +wss://mk.absturztau.be +wss://social.ornella.xyz +wss://left-tusk.com +wss://bofh.social +wss://a11y.social +wss://shroomslab.net +wss://relay2.nostr.vet +wss://mugicha.club +wss://laserbeak.local:4848 +wss://annihilation.social +wss://humble.cafe +wss://nostr.relay.damus.io +wss://nostr.milol.lol +wss://nostr.blimpme.app +wss://noc.social +wss://wetdry.world +wss://nostr.taxi +wss://nostr.21-bitcoin.org +wss://relay.llevotu-bitcoiners.info +wss://pl.kitsunemimi.club +wss://djsumdog.com +wss://citadel.local:4848 +wss://federate.blogpocket.com +wss://chaos.social +wss://mastodon.me.uk +wss://oxtr.dev +wss://misskey.cloud +wss://varishangout.net +wss://lacosanostr.com +wss://willem.currycash.net:4848 +wss://lightniningrelay.com +wss://queer.party +wss://lightning.relay.com +wss://mastodon.nl +wss://purplepag.es +wss://cupoftea.social +wss://bitcoiner.socialwss +wss://relay.current.io +wss://sigmoid.social +wss://wandering.shop +wss://braydmedia.de +wss://quey.la +wss://nostr.zebeedee.cloud +wss://nostr-2.zebeedee.cloud +wss://artsio.com +wss://nostr1676031941328.app.runonflux.io +wss://arsip.ddns.net +wss://relay.nostrcitadel.org +wss://relay.nostr-citadel.org +wss://nostr-citadel.org +wss://blastr.f7z.io +wss://nostr.myowndamnnode.com +wss://snowdin.town +wss://nostr.zxcvbn.space +wss://relay.notmandatory.org +wss://bitcoin.social +wss://friendsofdesoto.social +wss://zirk.us +wss://digipres.club +wss://nostr-test.elastos.io +wss://nostr.onsat.org +wss://damus.relay.io +wss://beefyboys.win +wss://nostrija-kari.heguro.com +wss://froth.zone +wss://ns.penseer.com +wss://relay.nostrical.com +wss://nostr.hoshizora.ch +wss://kunigaku.github.io +wss://nostr.shino3.net +wss://umbrel.tailbb128.ts.net:4848 +wss://tailbb128.ts.net:4848 +wss://fedi.twoshortplanks.com +wss://filter.nostr.winebroadcasttrue +wss://nostr.doufu-tech.com +wss://relay.hodl.haus +wss://pgh.social +wss://coeditor-congested.fractalnetworks.co +wss://mastodon.podaboutli.st +wss://frenfiverse.net +wss://nostr.f4255529.fun +wss://nostream.megadope.snowinning +wss://kiritan.work +wss://forever21.lol +wss://zitron.net +wss://mastodon-swiss.org +wss://relay1.current.fyi +wss://nostr.plebs.com +wss://multiplextr.corocal.social +wss://nostr.zedebee.cloud +wss://nostr.mutinywallet.comisntbanned.addthatonesotheycangetnotesrelayedtotherestofthenetworkfrominsideofchina +wss://mastodon.mit.edu +wss://relaynostrati.com +wss://relaynostr.band +wss://relaynostr.info +wss://relaychenxixian.cn +wss://relaysnort.social +wss://relaynostr.com.au +wss://nostr-tbd.website +wss://relay.hoshizora.ch +wss://social.balsillie.net +wss://strangeobject.space +wss://relay.nvote20.co +wss://fla.red +wss://urusai.social +wss://chad.polytechnic.com +wss://robo358.com +wss://conxole.io +wss://relay.ohbe.me +wss://nostr.bitcoiner.com +wss://www.mutinywallet.com +wss://x.9600.link:10070 +wss://a11y.info +wss://homelab.host +wss://k65qz57zx4sw24fow2bvchjgmpjqljj4cp3oa7dtpbbprjifsdotggid.local +wss://relay.vtuber.directory +wss://x.9600.link:8000 +wss://nostr.plebs.win +wss://renkontu.com +wss://nost.massmux.com +wss://submarin.online +wss://social.librem.one +wss://relai.kongerik.et +wss://mstdn.io +wss://astral.swiss-enigma.ch +wss://stereophonic.space +wss://relayer.pleb.social +wss://mastodon.nz +wss://nostr.nostr.de +wss://nostr.thezap.club +wss://proxy.shroomslab.net +wss://pfr24mrpxowclhm4y6adu36kbo3erx7gskzyfqqhnhfpdkdmylpfgkyd.local +wss://nostr.hodl.haus +wss://vtdon.com +wss://relay.nost.band +wss://fnxwipsg3lfzij64lvjgmutvkkpd7eo2mr2khxkofyywf3vsvbk73jad.onion +wss://fnxwipsg3lfzij64lvjgmutvkkpd7eo2mr2khxkofyywf3vsvbk73jad.local +wss://md.hugo.nostr +wss://boks.moe +wss://truthsocial.co.in +wss://mastodon.xyz +wss://relay.universalname.space +wss://relay-nostr.wirednet.jp +wss://fedi.pawlicker.com +wss://favcalc.com +wss://rot13maxi.com +wss://awayuki.net +wss://mazinkhoury.com +wss://g0v.social +wss://shpposter.club +wss://a.lufimianet.jp +wss://pura20vida.nostr.land +wss://sotalive.net +wss://sendsats.lol +wss://vida.page +wss://wagvwfrdrikrqzp7h3b5lwl6btyuttu7mqpeji35ljzq36ovzgjhsfqd.onion +wss://uec2cmjauzufrtlq6wq6l2ujfncdvo3suezz423gsvz5xvhehm2mcgid.onion +wss://mastodon-belgium.be +wss://rejecttheframe.xyz +wss://nogood.store +wss://getaiby.com +wss://plebchain.club +wss://nostrverified.com +wss://x.9600.link +wss://n0p0.shroomslab.net +wss://orangemakura.xyz +wss://jamw.net +wss://7ab7qqbj2dw3pjnkoskgsfn4ikqc7orwnkpmcfjmeobw63kf4zgykjid.local +wss://snabelen.no +wss://floss.social +wss://mastoot.fr +wss://kmc-nostr.amiunderwater.com +wss://hodl.camp +wss://xmr.usenostr.com +wss://nostr-pub.wellorn.net +wss://gudako.net +wss://ryona.agency +wss://kafeneio.social +wss://massmux.com +wss://freezepeach.online +wss://nostream-production-f83d.up.railway.app +wss://taobox.pub +wss://mastodon.radio +wss://einundzwanzig.relay.com +wss://journa.host +wss://social.here.blue +wss://toot.wales +wss://staging.nostr.com.se +wss://pleroma.soykaf.com +wss://berserker.town +wss://zapforart.site +wss://forall.social +wss://nostrja-kari.heguro.comyee +wss://higheredweb.social +wss://social.gnuhacker.org +wss://the.hodl.haus +wss://ng4jk6yiqgfczo4wyxszuj7w6jok3fptehu533o3mlzs3vph3dvjfdid.onion +wss://nostr.mtpx.ovh +wss://relay.coollamer.com +wss://glasgow.social +wss://fedi.absturztau.be +wss://nostr.frostr.xyz +wss://relay.runningnostr.lol +wss://relay2.vtuber.directory +wss://nerdculture.de +wss://nostr-relay.untethr.meoperator +wss://nostr.verif-slothy.win +wss://nostr.pub +wss://social.process-one.net +wss://invillage-outvillage.com +wss://otofu.uk +wss://universe.nostrich.landlangenlangpt +wss://mastodon.iriseden.eu +wss://frighteningdeafeningagent.nailuogg.repl.co +wss://obo.sh +wss://relay.hodlhaus.net +wss://rdrama.cc +wss://nostr.packetlostandfound.us +wss://test.relay +wss://mastodonbooks.net +wss://southflorida.ninja +wss://blob.cat +wss://tooting.ch +wss://relay.pineapple.pizza +wss://relay.nostr.directory +wss://relar.nostr.bg +wss://reisen.church +wss://relay.honk.pub +wss://nostr.rsfriedl.com +wss://relay.nort.social +wss://1611.social +wss://the.hodl.house +wss://relayable.com +wss://fedi.syspxl.xyz +wss://nostrpub.yeghro.site +wss://skr5bbrgzfnideglw4cs2iw6au2jm2b7gupocxbmkv5qopo6rcitmiqd.local +wss://a2mi.social +wss://status.relayable.org +wss://toot.blue +wss://btcqspp5dl4rlgl5pomcyv3odfeki7a5zrmjoekyu5vsoqz5bth4e7yd.onion +wss://bitcoinr6de5lkvx4tpwdmzrdfdpla5sya2afwpcabjup2xpi5dulbad.onion +wss://7tdom3xuus7ekv423ul46w3j43zyixjj54yoe62bndpcrgii3adeppid.onion +wss://dnze4ekho2kuiejwatjw5omeprtmdaum2ukok52roiu5rztii3rp2aid.onion +wss://53snncs7vegargpaardbxjnii2oan3xpmbeaf6czwoqa2axz5mvbsjid.onion +wss://fnqdhz3df33da6wxg7jskvumd5rjn3nknln6ecun7uwwysc7vkwkjgid.onion +wss://relay.thefockinfury.wtf +wss://silliness.observer +wss://freak.university +wss://piaille.fr +wss://nostr.weking.tk +wss://f.reun.de +wss://radixrat.com +wss://hostux.social +wss://chat.freenode.net +wss://no.str..cr +wss://nostr.inoata.cc +wss://kappa.seijin.jp +wss://floyds.io +wss://mast.dragon-fly.club +wss://zbd.ai +wss://misc.name +wss://pdx.social +wss://0w0.is +wss://d6jvu2tev2rblkuzgu4ydw2413jizr53j26ut47hxpykvtusbvekhiid.onion +wss://d6jvu2tcv2rblkuzgu4ydw24l3jizr53j26ut47hxpykvtusbvekhiid.onion +wss://drcassone.social +wss://mastodon.energy +wss://rayci.st +wss://ischool.social +wss://nostr.halfway2forever.com +wss://relay.nostr.rocks +wss://nostr.stoner.com +wss://2nodez.com +wss://rs.nostr-x.com +wss://schleuss.online +wss://thrashzone.org +wss://relay.nostrgraph.com +wss://relay.2nodez.com +wss://occult-zuki.com +wss://mastodon.lithium03.info +wss://bigbadpc.local:4848 +wss://social.gr0k.net +wss://nostr.wirednet.jp +wss://relay.plebster.com +wss://bitcoin.nostr +wss://mastodon.im +wss://brb..io +wss://nostr.sandwhich.farm +wss://relay.nos.lol +wss://beta.nostr.v0l.io +wss://eden.nostr.space +wss://powerlay.xyz +wss://rap.social +wss://relay.mutinywallet.com +wss://rogue.earth +wss://600.wtf +wss://klabo.blog +wss://petrikajander.com +wss://tgkzmdd.help +wss://nostr.red +wss://brb.lol +wss://jz2l2bf6f6wssdqwkg7ogthkc5i3ymyiwkaz3tbhff6ro3h3zqddekyd.onion +wss://mstdn.mini4wd-engineer.com +wss://nostr.exposd +wss://nostr.a-ef.org +wss://computerfairi.es +wss://social.targaryen.house +wss://o3o.ca +wss://walkah.social +wss://cosocial.ca +wss://filter.nostr.band +wss://relais.nostrview.com +wss://gigaohm.bio +wss://dobbs.town +wss://bark.lgbt +wss://mastodon.gal +wss://snug.moe +wss://genomic.social +wss://relay.orangepilldev.com +wss://social.sdf.org +wss://social.camph.net +wss://mstdn.poyo.me +wss://nein.lol +wss://nostr.i00.org +wss://kemono.ink +wss://mu.zaitcev.nu +wss://libera.site +wss://ca.hibi-tsumo.com +wss://social.bund.de +wss://xscape.top +wss://social.lol +wss://birds.town +wss://arnostr.com +wss://nostr.33co.de +wss://relay.nostr.lighting +wss://metadata-contacts-relays.pages.dev +wss://webs.node9.org +wss://pleroma.elementality.org +wss://suya.place +wss://livellosegreto.it +wss://peoplemaking.games +wss://nattois.life +wss://typo.social +wss://neutrine.com +wss://ragner-relay.com +wss://wss.nostr.uselessshit.co +wss://wss.nostrue.com +wss://relay.nvote.co:433 +wss://disobey.net +wss://rneetup.com +wss://arnostr.com:8433 +wss://relay.uxto.one +wss://relay.hackerman.pro +wss://thisis.mylegendary.quest +wss://poliversity.it +wss://sats.lnaddy.com +wss://rs2.abaiba.top +wss://rs1.abaiba.top +wss://rs2.abaiba.top.abaiba.top +wss://social.matarillo.com +wss://nostr01.counterclockwise.io +wss://backup.local:4848 +wss://touhou.vodka +wss://mi-wo.site +wss://nostr.f7z.io +wss://alive.bar +wss://strfry.nostr-x.com +wss://mastodontti.fi +wss://nostr.wellorder.net +wss://y.9600.link:8000 +wss://ephemrelay.mostr.pub +wss://byc-italia.online +wss://fissionator.com +wss://stranger.social +wss://eupolicy.social +wss://nostr-desktop.local:4848 +wss://aoir.social +wss://mstdn.plus +wss://nostrproxy.io:3333 +wss://mastodon.hams.social +wss://jorts.horse +wss://metalhead.club +wss://dice.camp +wss://mstdn.y-zu.org +wss://loffchain.pub +wss://mastodon.llarian.net +wss://nostr-relay2.thefockinfury.wtf +wss://2g2jzcfgq5lcrceuq23lmya2drm3ku5qmqimr3bvu3amol55vidctrad.onion +wss://mastodon.au +wss://bgme.me +wss://nostr.badran.xyz +wss://nostr.coincreek.com +wss://nostream-test.up.railway.app +wss://relay.blackthunder.click +wss://relay.grorp.com +wss://atomicpoet.org +wss://iddqd.social +wss://gusto.masto.host +wss://lifehack.social +wss://blorbo.social +wss://freecumextremist.com +wss://13bells.com +wss://rsslay.nostr.netrelay +wss://relay.zerosequioso.com +wss://nauka-relay.herokuapp.com +wss://nostr.nofdeofsven.com +wss://out.of.milk +wss://cawfee.club +wss://r.relay.fan +wss://alo.ottonove891.cf +wss://keinoha.tailnet-0240.ts.net +wss://nostr.paralelnipolis.cz +wss://tuiter.rocks +wss://elizur.me +wss://nostr-dev.newstr.io +wss://discuss.systems +wss://blahaj.zone +wss://mastodon.art +wss://makersocial.online +wss://gamepad.club +wss://nostr.flameofsoul.ru +wss://dmv.community +wss://relay.nostr.com +wss://nostr-desktop.saiga-shark.ts.net:4848 +wss://nostrfoxden.ddns.net:4848 +wss://soc.umrath.net +wss://ravenation.club +wss://oisaur.com +wss://nostr-relay.net +wss://social.mikutter.hachune.net +wss://lewacki.space +wss://fediscience.org +wss://todon.eu +wss://nuccy-nuc7i5bnk.local:4848 +wss://games.gamertron.net:4848 +wss://fiedlerfamily.net +wss://postnstuffds.lol +wss://nostr.planetary.social +wss://worldkey.io +wss://hcommons.social +wss://gymp7qquljs47xbbvs47hkptnyyzegy2jkst26mkjxaciifqffjatqid.onion +wss://rs3.abaiba.top +wss://sudo-nostr.com +wss://satgag.site +wss://nostr.lnbitcoin.cz +wss://relay20nostrplebs.com +wss://2pbkpndvpeebljfvjew6auq63lndzszqnntct5aqfmazslerzxe75kad.onion +wss://dragonchat.org +wss://welcome.nostr.wine +wss://relay.nostr.land +wss://social.linux.pizza +wss://dnppj4kopczovvzvpzmihv2iwe5wt3gbrxjnltjc2zdjpttrdz4owpad.onion +wss://potofu.me +wss://nostrbr.online +wss://mastorol.es +wss://notebook.taild34d0.ts.net +wss://t.aqn.jp +wss://nostr.mutinywallet +wss://wcone.nostr.wine +wss://norden.social +wss://eostagram.com +wss://shigusegubu.club +wss://toot.jkiviluoto.fi +wss://kiwifarms.cc +wss://swiss-talk.net +wss://v532btfg2fb4za2g476a7w23pgpkllc7uq274wqtktwjogt5ynb3ukqd.local +wss://mstdn.maud.io +wss://arc1.arcadelabs.com +wss://nostr.jp +wss://relay-jp.nostr.wirrdnet.jp +wss://climatejustice.social +wss://witter.cz +wss://mastodon.pnpde.social +wss://ttrpg-hangout.social +wss://beehaw.org +wss://thecanadian.social +wss://nostr.fbxl.net +wss://relay.sandwich.farm +wss://nostr.olwe.link +wss://botsin.space +wss://zeroes.ca +wss://photog.social +wss://paid.nostr.lc +wss://free.nostr.lc +wss://test.nostr.lc +wss://gzanlkgurj7zd3psqms3da4vrw4imurnyyzaycfuiiug7elqow7xlayd.onion:5051 +wss://masto.nu +wss://mastodon.uy +wss://bit.relay.center +wss://offchain.relay.center +wss://damus.relay.center +wss://wine.relay.center +wss://eden.relay.center +wss://moth.social +wss://nostr.masmux.com +wss://chrome.pl +wss://mastodon.ktachibana.party +wss://ak.kawen.space +wss://mementomori.social +wss://relay.s3x.social +wss://lnbits.michaelantonfischer.com +wss://yof23ggqmert72c5wcl5qglphapy3o2xjdedtkbrn2dt5rbae2s7f6qd.onion +wss://relay.snort.socail +wss://post.lurk.org +wss://yiff.life +wss://q3zaylwjjhq77yzx34lbydz26szzjljberwetkjgxgsapcekrpjzsmqd.onion +wss://lnbits.b1tco1n.org +wss://welcome.nostr.relay +wss://sound-money-relay.denizenid.com +wss://carnivore-diet-relay.denizenid.com +wss://africa.nostr.joburg +wss://nostr.jolt.run +wss://nostr.chainbits.co.uk +wss://ithurtswhenip.ee +wss://nostr.cloudversia.com +wss://relay1.east.us.nostr.btron.io +wss://ca.orangepill.dev +wss://pdx.land +wss://linh.social +wss://okla.social +wss://androiddev.social +wss://spore.social +wss://mastodo.fi +wss://kabedon.space +wss://nost.inosta.cc +wss://relay2cdamus.io +wss://nostr.openhoofd.nl +wss://dragonscave.space +wss://genart.social +wss://dewp.space +wss://layer8.space +wss://qou7zzll2mxx2ehl73n6pptmhizl5b3entowljlin3sqhcvltxdtlmad.onion:5051 +wss://nostr.wines +wss://relay.snort.relay.ryzizub.com +wss://pixelfed.de +wss://nostr.holyscapegoat.com +wss://nostr.einunzwanzig.space +wss://nostr.hifish.org +wss://colearn.social +wss://topspicy.social +wss://mastodon.neat.computer +wss://relay.nostr.hach.re +wss://nostr.dakukitsune.ca +wss://7ab7qqbj2dw3pjnkoskgsfn4ikqc7orwnkpmcfjmeobw63kf4zgykjid.onion +wss://esq.social +wss://famichiki.jp +wss://tribe.net +wss://masto.nobigtech.es +wss://umbrel-nuc.local:4848 +wss://mastodon.cocoasamurai.social +wss://debian.taildd32b.ts.net:4848 +wss://vlt.ge +wss://relay.johnnyasantos.com +wss://snort.relay.center +wss://nb.relay.center +wss://waag.social +wss://concentrical.com +wss://stat.rocks +wss://oransns.com +wss://relay-jpp.nostr.wirednet.jp +wss://oc.todon.fr +wss://jundow.gitlab.io +wss://neurodifferent.me +wss://jazztodon.com +wss://nostrich.friendship +wss://indieauthors.social +wss://werunbtc.com +wss://frogtalk.lol +wss://pop-os.local:4848 +wss://fediver.de +wss://d6qxo55dhms6revgrmbindvb5ejd3gw5hrji7ylkm6khghii3hjs3uyd.onion +wss://eldritch.cafe +wss://karlsruhe-social.de +wss://social.yl.ms +wss://nostr.mycloudhouse.duckdns.org +wss://nostr.otc.sh +wss://nya.social +wss://relay2.nostrchat.io +wss://relay1.nostrchat.io +wss://nostrja-world-relays-test.heguro.com +wss://ndk-relay.local +wss://reespeech.casa +wss://pleroma.atyh.cc +wss://lawfedi.blue +wss://akkoma.jasminetea.uk +wss://peeledoffmy.skin +wss://plush.city +wss://astrodon.social +wss://samenet.social +wss://toot.bike +wss://mi.yukioke.com +wss://social.growyourown.services +wss://mastodon.nu +wss://lou.lt +wss://functional.cafe +wss://relaydamus.io +wss://coma.social +wss://social.fbxl.net +wss://biplus.social +wss://toots.matapacos.dog +wss://psychoet.ml:3250 +wss://danserver.equipment +wss://nostr.lacrypta.com.ar +wss://wonkodon.com +wss://nostr.seankibler.com +wss://autistics.life +wss://cambrian.social +wss://rvqkqr5kl3dvvxyn67rfowcnvoflx4zby5tjbysavym4ycckti4dbjyd.onion +wss://swiss.nostr.lc +wss://snac.saifulh.online +wss://loma.ml +wss://nostr.privoxy.io +wss://366.koyomi.online +wss://mastodon.stormy178.com +wss://podcastindex.social +wss://bitcoiner.socia +wss://fedi.ml +wss://replayable.org +wss://nostr.schroomslab.net +wss://nostr.global.fans +wss://relay.weedstr.net +wss://vocalodon.net +wss://relay.nostr.bandadd +wss://nostr.oxtr.devadd +wss://jarvis.taild68e2.ts.net:4848 +wss://t7jvqwu35hneszx7fihsprbcpwonlcfnsjr4xtn6shqgwbv324w4gdid.onion +wss://stonez.local:4848 +wss://notrustverify.ch +wss://woof.group +wss://mastodon.floe.earth +wss://lnbits.plebtag.com +wss://kpop.social +wss://relay.wavlake.com +wss://mastodon.sharma.io +wss://travelpandas.fr +wss://alphapanda.prowss +wss://relay.saes.io +wss://barelysocial.org +wss://masto.komintern.work +wss://norcal.social +wss://nostr.zbd.gg +wss://mk.outv.im +wss://mstdn.mx +wss://col.social +wss://nostr.freedom.fi +wss://filter.nostr.winebroadcasttrueglobalall +wss://eden.nostr.landv +wss://me.dm +wss://emacs.ch +wss://winonostr.wine +wss://infoplebstr.com +wss://mas.towss +wss://gruene.social +wss://relay.freeplace.nl +wss://itis.to +wss://bsky.social +wss://lnbits.thefockinfury.wtf +wss://5xxkt7zvmh4zdsjw64lgvchjdlrrgw4w2huujiiud35qms6gnkn5azad.onion +wss://eientei.org +wss://artisan.chat +wss://nustr.mom +wss://relay.nostrhraph.net +wss://shitposter.club +wss://nostril.cam +wss://nostr.spaceshell.xyz +wss://relay.wtr.app +wss://tdd.social +wss://d3meec25b53kegrnjmtmtyynikbkmuxf4jqgtk3sonjs6e62hpaezyqd.onion +wss://tkz.one +wss://freerelay.xyz +wss://nfdn.betanet.dotalgo.io +wss://mitra.social +wss://hablanews.io +wss://calle.wtf +wss://voskey.icalo.net +wss://nostr.sloyhy.win +wss://framapiaf.org +wss://nostrnodeofsven.com +wss://ciberlandia.pt +wss://gnusocial.net +wss://relay.s3x.socia +wss://paste.2nodez.com +wss://union.place +wss://bofh.socia +wss://sovbit.dev +wss://lnbits.btc-payserver.eu +wss://osna.social +wss://im-in.space +wss://junxingwang.org +wss://relay.nostr.wirednet.jpcheck +wss://libranet.de +wss://fedisnap.com +wss://woodpecker.social +wss://gensokyo.town +wss://social.imirhil.fr +wss://links.potsda.mn +wss://law-and-politics.online +wss://nostrich.bar +wss://tweesecake.social +wss://nostr.kisiel.net.pl +wss://relay.kisiel.net.pl +wss://calckey.social +wss://nostr.cercatrowa.me +wss://meganekeesu.tokyo +wss://lndiscs.duckdns.org +wss://omochi.xyz +wss://wue.social +wss://nostr.libreleaf.com +wss://rusnak.io +wss://rsslay-production.up.railway.app +wss://nostr.yuhr.org +wss://bod4ojj37fneith2setv3qjbii563wesbjqgdipdz4ag6voic2xk5iad.onion +wss://fediverse.blog +wss://pouet.chapril.org +wss://baq5ufl2rnczpalnoqabxwpjm3kvhzduwgvptxzx7yq37oqdbgf65syd.local +wss://baq5ufl2rnczpalnoqabxwpjm3kvhzduwgvptxzx7yq37oqdbgf65syd.onion +wss://cryptodon.lol +wss://nostr.debancariser.com +wss://mizunashi.hostdon.ne.jp +wss://relay.deezy.io +wss://bbq.snoot.com +wss://historians.social +wss://mi.mashiro.site +wss://mastodonpost.social +wss://nostrpub.welliorder.net +wss://social.cologne +wss://metapixl.com +wss://wandzeitung.xyz +wss://lightninhrelay.com +wss://techopolis.social +wss://lnbits.btcpins.com +wss://purplenostrich.com +wss://onewilshire.la +wss://sself.co +wss://anygemini13.blogs.sapo.pt +wss://federated.press +wss://metadata.nostr.com +wss://nostr.hodl.ar +wss://goreslut.xyz +wss://mastodon.com.tr +wss://climatejustice.global +wss://brotka.st +wss://sueden.social +wss://mstdn.fr +wss://abid.cc +wss://lnbits.fuckedbitcoin.com +wss://meow.social +wss://nostr.rehab +wss://mstdn.media +wss://nodeo1.nostress.cc +wss://nostrmassmux.com +wss://sauropods.win +wss://civilians.social +wss://pnw.zone +wss://zebeedee.cloud +wss://nostr.walletofsatishi.com +wss://aufovmqaxj5nhqmtorhgpogdjxefhkff25cbyyjt2sub3vwg6b6rplid.onion +wss://forfuture.social +wss://76f67qcwxsxpz7cfozlzunota2ejqznpldc5pnqtyq233hjpjzrmlfid.local +wss://toot.garden +wss://umbrel.tail9dfb.ts.net:4848 +wss://mastodon.chasem.dev +wss://misskey.pm +wss://merovingian.club +wss://chirp.enworld.org +wss://paid.no.str.ce +wss://masto.bike +wss://masto.1146.nohost.me +wss://eosla.comno-str.orgrelay.zeh.appno-str.orgrelay.zeh.app +wss://nixnet.social +wss://pay.zapit.live +wss://respublicae.eu +wss://nekomiya.net +wss://mastodon.internet-czas-dzialac.pl +wss://plushies.social +wss://lnb.openchain.fr +wss://mastodon.lol +wss://social.rebellion.global +wss://ruhr.social +wss://mi.farland.world +wss://pkutalk.com +wss://systemli.social +wss://nostr.minimue81.selfhost.com +wss://mastodon.la +wss://everything.happens.horse +wss://pagan.plus +wss://clacks.link +wss://u-tokyo.social +wss://fediverse.projectftm.com +wss://mastodon.bachgau.social +wss://social.kabi.tk +wss://ty3zdjkwlxo4zah6tgdoolznjcbvkhxpcvjyqe2buxeg23hbeyvr3rad.local +wss://pleroma.wakuwakup.net +wss://social.horrorhub.club +wss://nostr.nightowlstudios.ca +wss://mastodon.ml +wss://relay.orangepillapp.com +wss://misskey.sup39.dev +wss://mfmf.club +wss://pokemon.mastportal.info +wss://gohan-oisii.net +wss://aipi.social +wss://nostr.semisol.com +wss://oslo.town +wss://relay.layer.systems +wss://naharia.net +wss://social.elbespace.de +wss://linuxrocks.online +wss://b81m3pf94ridtry53g8ufyyrjtjaoxgbyjbs5k8qrqkr1whocxiy.loki:8080 +wss://lvl01.tater.ninja +wss://kinky.business +wss://relay.bitblockboom.com +wss://fedi.omada.cafe +wss://social.secret-wg.org +wss://celebrity.social +wss://weirdo.network +wss://mastodon.design +wss://berlin.social +wss://misskey.yukineko.me +wss://mindmachine.688.org +wss://sackheads.social +wss://a.farook.org +wss://social.ridetrans.it +wss://nostr-2.crypticthreadz.com +wss://test.itas.li +wss://fashionsocial.host +wss://ordinary.cafe +wss://social.arinbasu.online +wss://nostr.crypticthreadz.com +wss://relay.zebedee.cloud +wss://nostr.pub.wellorder.net +wss://09d4-5-161-189-144.ngrok-free.app +wss://andalucia.social +wss://udongein.xyz +wss://squeet.me +wss://mastodon.org.uk +wss://guild.pmdcollab.org +wss://relay.fi +wss://black.nostrscity.club +wss://relay.darker.to +wss://denostr.paiya.app +wss://noste.lu.ke +wss://wss.node01.nostress.cc +wss://theverge.space +wss://swiss.social +wss://relay.webstr.org +wss://nostr.shsbt.xyz +wss://relay.nostr.mom +wss://bitcoinmaximlaists.online +wss://relay.openhoofd.nl +wss://toot.aquilenet.fr +wss://toot.ale.gd +wss://relay.devstr.org +wss://lounge.town +wss://amala.schwartzwelt.xyz +wss://planetasieve.com.br +wss://alcrypt.ru:20911 +wss://webzero.grin.plus:8080 +wss://pylons.lightlns.com:28556 +wss://etourneau.fr:28343 +wss://sentie.relay.rts.network +wss://hermes.boarstudios.com +wss://non-central.pw +wss://nostrum.casa +wss://press.coop +wss://neovibe.app +wss://mstdn.starnix.network +wss://nostr.ameristraliagov.com +wss://cryptodon.chat +wss://umbrell.local:4848 +wss://mastodon.codingfield.com +wss://fe.disroot.org +wss://national.catposting.agency +wss://mastodon.pinewoodroad.net +wss://podcasts.social +wss://20nostr.semisol.dev +wss://nostr.oxtr.net +wss://mstdn.o-nature-culture.net +wss://dearcoati6.lnbits.com +wss://die-partei.social +wss://donotban.com +wss://creative.ai +wss://metaskey.net +wss://spacey.space +wss://node01.nostreess.cc +wss://node01.nostress.co +wss://niscii.xyz +wss://3gkpphcfwb6w5iq6axnmlbvr7pz2t37uy4ofocyijzttzrbz4jy43fid.onion +wss://3gkpphcfwb6w5iq6axnmlbvr7pz2t37uy4ofocyijzttzrbz4jy43fid.local +wss://sportsbots.xyz +wss://videos.lukesmith.xyz +wss://nostr.btcfreedom.ca +wss://gardenstate.social +wss://bg-btc.local:4848 +wss://0fa53e299287.ngrok.app +wss://bird.makeup +wss://nlayer.lbdev.fun +wss://relay.queiroz.vip +wss://mstdn.business +wss://osage.moe +wss://botrelay.com +wss://filter.wine +wss://gingadon.com +wss://noncentral.pw +wss://honi.club +wss://xn--baw-joa.social +wss://nostr.semisol.devwss +wss://relay.iris.to +wss://mynostrrelay.deno.dev +wss://social.heise.de +wss://vavursybkbgfyow7nnst5jnqsj2xyteusf3zeerbjdizq6y7h25v4syd.onion:5051 +wss://vavursybkbgfyow7nnst5jnqsj2xyteusf3zeerbjdizq6y7h25v4syd.onion:5050 +wss://relao.nostr.bg +wss://phpc.social +wss://mastodon.kylerank.in +wss://gameliberty.club +wss://rot.gives +wss://www.nostrweb.xyz +wss://ligma.pro +wss://mastodon.grin.hu +wss://geeknews.chat +wss://devdilettante.com +wss://relay.nosr-latam.link +wss://nosr.bitcoiner.social +wss://raru.re +wss://create-key.net +wss://lgbtqia.space +wss://fluffy.family +wss://mas.town +wss://bird.froth.zone +wss://akkoma.cryptoschizo.club +wss://relay.ramus.io +wss://40two.site +wss://relay.40two.site +wss://vis.social +wss://mk.paritybit.ca +wss://nyan.network +wss://ln.weedstr.net +wss://wikis.world +wss://social.fringe.com +wss://umbraxenu.no-ip.biz +wss://heads.social +wss://tsqdakwo4dh5ej3llsi52ftxfbialteu3jm4cmvxaksl3psbyeoyxxqd.onion +wss://jameliris.to +wss://mastodon.thirring.org +wss://miniwa.moe +wss://welcom.nostr.wine +wss://nostr.vulpem.comwss +wss://relay.semisol.dev +wss://kitsunes.club +wss://songbird.cloud +wss://nostr.wyssblitz.org +wss://libera.tokyo +wss://trpger.us +wss://comam.es +wss://nostr-pub.semisol.devaddittoyourrel +wss://social.dev-wiki.de +wss://ostfrie.se +wss://darmstadt.social +wss://nostr.cx.ms +wss://alentours.cc +wss://nostr.kleofash.eu +wss://gib.social +wss://test23.hifish.org +wss://rapemeat.solutions +wss://filter.stealth.winebroadcasttrue +wss://nostr.montre +wss://grumble.social +wss://nostr.roli.social +wss://primarycare.app +wss://hodlr.rocks +wss://superlinks.me +wss://mastodon.lawprofs.org +wss://tictoc.social +wss://nostest.dojotunnel.online +wss://kafka.icu +wss://nostr.lanparty.one +wss://filter.nostr.wineglobaltrue +wss://social.b10m.net +wss://worm.pink +wss://nostr-test.cx.ms +wss://nostrverifired.com +wss://relay.nostrss.re +wss://eliitin-some.fi +wss://dju.social +wss://jeremy.hu +wss://stream.criminallycute.fi +wss://nostr.0x50.dev +wss://n.s.nyc +wss://n.8.s.nyc +wss://relay.rocks +wss://relay.fiatjaf.com +wss://n-lan.s.nyc +wss://sciences.social +wss://nostr.swiss-enigma.com +wss://quietplace.xyz +wss://universe.nostrich.landlangenlangzh +wss://5280.city +wss://feddit.de +wss://base.lc +wss://social.medusmedia.com +wss://umha4zl6xk62a4dous6e7tq4qlmt462hlzs2su33en6qrvtvs3hkjgid.onion +wss://etorneau.fr:28343 +wss://foggyminds.com +wss://neurodiversity-in.au +wss://nostr.hendrixson.net +wss://ramen-fsm.eu.org +wss://www.nostrical.com +wss://feedbeat.me +wss://relay.bsky.social +wss://babka.social +wss://mastodontech.de +wss://commiespace.duckdns.org +wss://openbiblio.social +wss://karkatdyinginagluetrap.com +wss://relay.fundr.vanderwarker.family +wss://hannover.town +wss://nostr.relay.info +wss://mastodon.tetaneutral.net +wss://cache2.primal.net +wss://nostr.petrkr.net +wss://ifwo.eu +wss://mastodong.lol +wss://venera.social +wss://wallets.fyoumoneypod.com +wss://nostr.relay-nokotaro.com +wss://social.exozy.me +wss://gqgjp2bun4opme6mepz3rrgprkw4xatb6h5ogayorqwi6sajsxcp5sad.local +wss://branle.netlify.app +wss://rsslay.fiat.jaf +wss://chrislace.damus.io +wss://relay.leafbodhi.com +wss://social.opendesktop.org +wss://relay.nostr.watch +wss://gearlandia.haus +wss://freiburg.social +wss://atlas.nostro.land +wss://nostr.io +wss://patrizio.tn.al +wss://chaintools.io +wss://kn.icu +wss://relaywithme.eu +wss://la-autopilot-this-end-up.dvm.email +wss://coinfinity.co +wss://assemblag.es +wss://qou7zzll2mxx2ehl73n6pptmhizl5b3entowljlin3sqhcvltxdtlmad.onion +wss://indigenouscreatives.social +wss://bookwyrm.social +wss://kokoro.shugetsu.space +wss://eden.nost.land +wss://misskey.gothloli.club +wss://sersleepy.com +wss://rsslay.nos.pink +wss://pettingzoo.co +wss://witches.live +wss://7craxnzfi42touzi23etut5qjzqro27sqcuottxj7opntcin4fstruad.onion +wss://mastodonsweden.se +wss://mv2k.com +wss://nostr.tchaicap.space +wss://relay.whoop.ph +wss://bitcoiner.nostr.social +wss://kinkyelephant.com +wss://www.superstork.org +wss://mastodon.iftas.org +wss://lea.pet +wss://zug.network +wss://homeserver.local:4848 +wss://frontrange.co +wss://sciencemastodon.com +wss://montereybay.social +wss://social.securecryptomining.com +wss://rssrelay.nostr.moe +wss://nostr.org +wss://nostr.tw +wss://nostr.hk +wss://wxw.moe +wss://mastodonmusic.social +wss://puntarella.party +wss://oyasumi.space +wss://drumstodon.net +wss://social.wikimedia.de +wss://iyasaretai.pw +wss://social.coletivos.org +wss://nostream.localtest.me +wss://ubuntu201.local:4848 +wss://masto.pt +wss://taiwan.riley-tech.net +wss://freeradical.zone +wss://blastrf7z.xyz +wss://onemorestop.photo +wss://frikiverse.zone +wss://toot.bldrweb.org +wss://electroverse.tech +wss://mstdn.games +wss://relay1.nostr.unitedfop.com +wss://gratefuldread.masto.host +wss://mk.gabe.rocks +wss://widerweb.org +wss://mastodon.eternalaugust.com +wss://lay.southeastasia.cloudapp.azure.com:445 +wss://me.ns.ci +wss://gnostr.th +wss://fritter.cn +wss://nex.cn +wss://nex.tw +wss://fritter.jp +wss://fritter.tw +wss://gnostr.cn +wss://mstdn.dk +wss://akkoma.simulacrum-emporium.eu +wss://dalliance.social +wss://toot.re +wss://avatastic.uk +wss://blastr20f7z.xyz +wss://the.voiceover.bar +wss://porcodon.net +wss://nostr.dncn.xyz +wss://nostr.dnxn.xyz +wss://relay.xmr.rocks +wss://d6egak3woofrixu26gr3utb5qezhkktavsuwlrfqaauu55lmpudxudqd.onion:5051 +wss://social.wuebbsy.com +wss://4kgwkcfzea2xhefsquktyxqyjf3rsxa7oo7hxbcs6k3xdpxznknydsqd.local +wss://4kgwkcfzea2xhefsquktyxqyjf3rsxa7oo7hxbcs6k3xdpxznknydsqd.onion +wss://tooters.org +wss://nostre.wine +wss://relay.xplive.local +wss://relay2.xplive.local +wss://4v5umvicfs6a7d3aiy67uu2ibttiuanl2cehfmv5qaorbojousbgkdad.onion +wss://pipou.academy +wss://opjk6jxrcyicuwhe62tqy6zwx776u7rfi6cqo6iodurjvege7piz5wqd.local +wss://mythology.social +wss://nostr.millou.lol +wss://ryogrid.net:7777 +wss://nost.debancariser.com +wss://fault.stsecurity.moe +wss://jan-optiplex-5040.local:4848 +wss://relay-jp.wirednet.jp +wss://mastodon.kitchen +wss://relay.mnethome.de +wss://verkehrswende.social +wss://nostr.gleeze.com +wss://dair-community.social +wss://shota.house +wss://kavlak.uk +wss://social.inex.rocks +wss://4v5umvicfs6a7d3aiy67uu2ibttiuanl2cehfmv5qaorbojousbgkdad.local +wss://startrekshitposting.com +wss://nostrfmar.ddns.net +wss://4yqp7gzuf15zfc3hpwhz3j5p2uarvdsnf75ovpdiqvyjdsmku771jfid.onion +wss://nostrgraph.net +wss://idolheaven.org +wss://mstdn.kemono-friends.info +wss://mastodon.bawue.social +wss://social.pmj.rocks +wss://ursal.zone +wss://nstr.milou.lol +wss://poweredbygay.social +wss://gochisou.photo +wss://lnb3.openchain.fr +wss://nostr.filmweb.pl +wss://nostr-word.h3z.jp +wss://blastr.f7z.xyzanotherinstanceofblastr +wss://shakedown.social +wss://nostr.bubu.hair +wss://hyper-nostr.inosta.cc +wss://ieji.de +wss://wawmartme.com +wss://nostr.kungfu-g.rip +wss://bozgor.org +wss://todon.nl +wss://nostpy.lol +wss://ostatus.taiyolab.com +wss://polsum.rocks +wss://freespeech.group +wss://im.allmendenetz.de +wss://shitpost.poridge.club +wss://twingyeo.kr +wss://social.platypush.tech +wss://rsslay-production-bc22.up.railway.app +wss://lonely.damus.io +wss://kirche.social +wss://cubalibre.social +wss://relay.txinito.xyz +wss://realy.orangepill.dev +wss://3zi.ru +wss://plebstr.com +wss://social.seattle.wa.us +wss://social.bim.land +wss://cubhub.social +wss://relay.nostr-x.com +wss://hispagatos.space +wss://node101.nostress.cc +wss://lsbt.me +wss://jgqaglhautb4k6e6i2g34jakxiemqp6z4wynlirltuukgkft2xuglmqd.onion +wss://nostdemo.dojotunnel.online +wss://f.cz \ No newline at end of file From d93a8d94d2e794795ca4f2d51706bf1705168a3f Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 22 Sep 2025 20:05:07 -0400 Subject: [PATCH 3/4] Reduces number of Notifications from random relays. --- .../nip01Notifications/FilterNotificationsToPubkey.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/FilterNotificationsToPubkey.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/FilterNotificationsToPubkey.kt index 9c528f4794..6d174e1d7b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/FilterNotificationsToPubkey.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/FilterNotificationsToPubkey.kt @@ -147,7 +147,7 @@ fun filterJustTheLatestNotificationsToPubkeyFromRandomRelays( Filter( kinds = SummaryKinds, tags = mapOf("p" to listOf(pubkey)), - limit = 500, + limit = 20, since = since, ), ), @@ -157,7 +157,7 @@ fun filterJustTheLatestNotificationsToPubkeyFromRandomRelays( Filter( kinds = NotificationsPerKeyKinds, tags = mapOf("p" to listOf(pubkey)), - limit = 500, + limit = 20, since = since, ), ), @@ -167,7 +167,7 @@ fun filterJustTheLatestNotificationsToPubkeyFromRandomRelays( Filter( kinds = NotificationsPerKeyKinds2, tags = mapOf("p" to listOf(pubkey)), - limit = 500, + limit = 20, since = since, ), ), From 054cfa0de95da2eb63511093903c974dbfa79a88 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Tue, 23 Sep 2025 00:07:59 +0000 Subject: [PATCH 4/4] New Crowdin translations by GitHub Action --- .../src/main/res/values-es-rES/strings.xml | 27 +++++++++++++++++-- .../src/main/res/values-sl-rSI/strings.xml | 12 ++++----- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/amethyst/src/main/res/values-es-rES/strings.xml b/amethyst/src/main/res/values-es-rES/strings.xml index 096e9ab2c2..78a43c082c 100644 --- a/amethyst/src/main/res/values-es-rES/strings.xml +++ b/amethyst/src/main/res/values-es-rES/strings.xml @@ -148,6 +148,7 @@ Error al guardar el video Cargar imagen Hacer una foto + Grabar un video Grabar un mensaje Grabar un mensaje Haz clic y mantén pulsado para grabar un mensaje @@ -163,6 +164,8 @@ Usuarios bloqueados Temas nuevos Conversaciones + Tablón + Cola de mods Notas Respuestas Tuyo @@ -437,6 +440,7 @@ No Lista de seguidos Todos los seguidos + Todas las cuentas a las que sigue el usuario Siguiendo a través de proxy A mi alrededor Global @@ -577,7 +581,7 @@ Relés Paquetes de seguimiento Lecturas - Algoritmos del feed + Algoritmos de fuentes Mercado Transmisiones en vivo Comunidades @@ -655,6 +659,8 @@ Explicación para los miembros Cambio de nombre para los nuevos objetivos. Pegar desde el portapapeles + URI de NIP-47 no válido + El URI %1$s no es un URI de inicio de sesión NIP-47 válido. Para la interfaz de la aplicación Tema oscuro, claro o del sistema Cargar automáticamente imágenes y GIF @@ -672,6 +678,9 @@ Contenido multimedia añadido a la galería del perfil Creado Reglas + Sobre nosotros + Directrices + Moderadores Iniciar sesión con Amber Actualiza tu estado Error al analizar el mensaje de error @@ -884,10 +893,13 @@ Carga de mensaje directo Configuración de relés Relés de inicio públicos + El usuario está publicando su contenido a estos relés Este tipo de relé almacena todo tu contenido. Amethyst enviará tus publicaciones aquí y otros usarán estos relés para encontrar tu contenido. Inserta entre 1 y 3 relés. Pueden ser personales, de pago o públicos. Relés de buzón de entrada públicos + El usuario está recibiendo notificaciones en estos relés Este tipo de relé recibe todas las respuestas, comentarios, me gusta y zaps de tus publicaciones. Inserta entre 1 y 3 relés y asegúrate de que acepten publicaciones de cualquier persona. Relés de buzón de entrada para mensajes directos + El usuario recibe mensajes directos en estos relés Inserta entre 1 y 3 relés para que te sirvan de buzón de entrada privado. Otros usarán estos relés para enviarte mensajes directos. Los relés del buzón de entrada para mensajes directos deberían aceptar cualquier mensaje de cualquier persona, pero solo te permiten descargarlos. Algunas buenas opciones son:\n - inbox.nostr.wine (de pago)\n - you.nostr1.com (relés personales; de pago) Relés privados Inserta entre 1 y 3 relés para almacenar eventos que nadie más pueda ver, como los borradores o la configuración de la app. Lo ideal es que estos relés sean locales o requieran autenticación antes de descargar el contenido de cada usuario. @@ -906,7 +918,7 @@ Relés en que confías para no necesitar una conexión Tor para Relés de proxy Relés de proxy - Relés recopiladores que la app debe usar para descargar tus feeds, como filter.nostr.wine. Esto reemplaza el modelo de bandeja de salida y hará que la app se conecte solo a los relés de tus listas. + Relés recopiladores que la app debe usar para descargar tus fuentes, como filter.nostr.wine. Esto reemplaza el modelo de bandeja de salida y hará que la app se conecte solo a los relés de tus listas. Relés de transmisión Relés de transmisión Relés que se especializan en enviar tus notas a todos los demás relés, como sendit.nosflare.com. Amethyst agregará este relé a todos los eventos nuevos que crees. @@ -1009,7 +1021,18 @@ Relé de chat Relé al que todos los usuarios de este chat se conectan Compartir imagen… + No se puede compartir la imagen, inténtalo de nuevo más tarde… Buscar hashtag: #%1$s No traducir del Los idiomas que se muestran aquí no se traducirán. Selecciona un idioma para eliminarlo y traducirlo de nuevo. + Pausar + Reproducir + Abrir menú desplegable + Opción %1$s de %2$s + Filtro del tablón, %1$s seleccionado + Filtro del tablón, %1$s + Informe de error encontrado + ¿Te gustaría enviar el informe de error reciente a Amethyst en un mensaje directo? No se compartirá información personal + Enviarlo + Este mensaje desaparecerá en %1$d días diff --git a/amethyst/src/main/res/values-sl-rSI/strings.xml b/amethyst/src/main/res/values-sl-rSI/strings.xml index 6435c791ff..7ed17546e3 100644 --- a/amethyst/src/main/res/values-sl-rSI/strings.xml +++ b/amethyst/src/main/res/values-sl-rSI/strings.xml @@ -2,8 +2,8 @@ Usmeri v QR kodo Pokaži QR kodo - Profilna slika - Tvoja profilna slika + Slika profila + Tvoja slika profila Skeniraj QR kodo Vseeno prikaži To sporočilo je skrito, ker je omenjena nekatera od skritih uporabnikov ali besed @@ -84,7 +84,7 @@ Za podpisovanje se je potrebno prijaviti s privatnim ključem "odgovoriti " " in " "v kanalu " - Profilna pasica + Pasica profila Plačilo uspešno Napaka pri razčlembi sporočila o napaki " Sledi" @@ -179,7 +179,7 @@ Za podpisovanje se je potrebno prijaviti s privatnim ključem Moderatorska vrsta Zapiski Pogovori - Tvoje + Vaše Galerija "Sledi" "Reportaže" @@ -736,7 +736,7 @@ Za podpisovanje se je potrebno prijaviti s privatnim ključem Denarnica za plačilo z \"lightning\" ni najdena. Prosimo, namestite \"lightning\" denarnico da boste lahko Zap-ali ostale Skrite besede Skrij novo besedo ali stavek - Profilna slika + Slika profila Prikaži profilne slike Uporabi možnost Fakture ni bilo mogoče plačati @@ -866,7 +866,7 @@ Za podpisovanje se je potrebno prijaviti s privatnim ključem Všečkaj Zap Spremeni hitre odzivne ikone - Profilna slika %1$s + Slika profila %1$s Rele %1$s Razširi seznam relejev Možnosti zapiska