From 7a280a3cde49fa7c6fdcd28e8310864940f61187 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 22 Sep 2025 19:44:51 -0400 Subject: [PATCH] - 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 d4f428a75..34e20e556 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 8b8627eb5..6e25285f0 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 7e3e34a6e..9713d7dd4 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 24cae52d3..6f940370e 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 91f63f94d..d11351b97 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 99db5b628..cce0af991 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 db649c198..200a49421 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 128c69420..47df83e68 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 1d54873fb..ce1d4428e 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 0168e90a1..8d0d989be 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 9862203d4..d686147ad 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 7ae55fbab..da67134d8 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 29c888d45..906c3b510 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 9224b615d..f10327af1 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 4165bc395..8a48aca82 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 53037cb48..094850ab3 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 6efe26d4a..8b66d2ce1 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 4b2defdcb..b9bdfdcb9 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 e711e8fe1..336610ae9 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 b000d16c0..468cedc6f 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 6846f275c..a513bedc8 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 ae60c2966..172ef6c1d 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 f5150e4bd..1e56a62a8 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 b203748b1..fd4d927f7 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 7026aca5a..03ba05a3d 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 3a1b5c1a5..cfd116e51 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 a91dd6e05..80061efe0 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 700e5fdc3..d16c67b3d 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 89d3eaa0a..dfad190c9 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 6e8769570..fab0e395e 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 0061c0385..186419e34 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 574a2345f..a36abd280 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 d4cc44f70..df51825bf 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 faae8ee70..d941acebf 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 000000000..b86a8c77b --- /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 94aba84e2..4ed3eb50d 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 04892f908..fd4bab976 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 842072115..f582734cf 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 5f1214f87..75fa41af7 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 70b4505ce..d30bc4551 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 38cf0aedd..0fdb4793a 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 965e58bfc..80c87c435 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 2bebd3094..1e747c091 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 73e5906d8..16f00e03d 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 f78ba1f2c..2b8f7e7bf 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 590c409d4..a92fceda0 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 41aff1c06..eabd77993 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 34805ebfd..312fd1e45 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 8773f12cd..b1d85a429 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 24052d620..7f057593a 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 d44cface2..936191085 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 d7d383198..c8b43ab5d 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 d84767041..61ad89609 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 fadcad035..7fc94d785 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 f3fc628e5..6c8daf2b2 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 af7fdaa96..0944a4360 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 c1c70ca53..d4c88552e 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 899495f67..6a81dcf37 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 578e912ed..8c254d660 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 e917a47fa..cd6675eca 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 83b7ca2a0..ac271a340 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 40debbe42..57e2e3425 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 706b75fc9..8a4c3bb4d 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 508678a25..0c6ba0610 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 ca94c6842..792efcb8a 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 7475b91ce..e77a5cbe4 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 2f78457f3..543cd8fce 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 1f406816c..2a22f7e54 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 d80d8faa9..8042d9124 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 f41639f2b..8e371a423 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 c814e07ea..dd2779157 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 44674d0b9..953fdf319 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 de6d05027..bd5a3274f 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 a9ae46535..1446702b0 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 27e0c3120..2072e87d2 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 2acbb3119..940a33de9 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 1d35148f7..e7ea8821c 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 3b0727d02..ba1949d02 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 36b457cd5..b6f3a2cd2 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 15f051305..1203cdd9a 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 bd71c9285..a10990720 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 5d31a668f..20e2e43de 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 e64baa708..42fca1995 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 ec055e448..8e6e1267e 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 e929a44c5..e35a1ecf0 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 8316c5620..93cdc5b88 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 1feed28b3..496b82e7b 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 915f3ff37..3ec0bd726 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 bb9a8474a..71e7b84c2 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 1bd5bf6dd..7edf943d2 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 2ff150571..546c8b0f7 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 56860511c..277d9450d 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 4a3d7d926..8cbeef972 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 cfc55e4d8..70a0c5455 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 c87d63492..b61ab0ea8 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 89b222886..e4f8384ec 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 745bc3f80..22ef301b7 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 b648047f3..c1583feb1 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 19b5821cc..fc565f539 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 cc0f365dd..f006c5962 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 1babc6c49..f79e60af7 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 afb2e8d2b..29d86b669 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 444b29791..9f5cfe255 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 424a3cd82..45d8269e2 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 94d4287aa..dd011f74f 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 f65550733..d97367448 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 ca9814468..1490c1d7d 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 55cf8147f..3520c41b0 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 2b8a9e1f4..85527e818 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 8a02c884f..b85db2ca2 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 9ac7dfe6b..40ce38396 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 6eab5aadb..4c223bf1b 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 0d0e67c3a..b81b3a6b6 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 0d8c32b19..641b7be15 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 a7698c60a..2b499f606 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 10f538290..f063cbd05 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 1e304ab32..2c901159e 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 6d6b55a9c..9b1f191f3 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 8a6d84cac..0d2b19196 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 279308bfc..c88f6d6fe 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 ac6c65960..222898aa8 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 a70b427f2..4be4fcb40 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 325a32730..72b9286f1 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 7ecbe1339..accd8d685 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 26d465a95..af7b4b419 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 385f538a0..908a5c160 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 29a0943ca..2ea414187 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 6ada3dda7..1328401a7 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 ae6e09a15..3ee67c5c7 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 e55fbd880..238f52c3b 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 f7473724a..cf5d6d14e 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 16060c726..c2ae95055 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 e403f4796..0c8a4a4ef 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 35209d6e8..eb16733a7 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 d33c8a121..2ccccdf26 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 0e69f6295..8cd1da73b 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 71e3ab8bc..da226558e 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 718b6e378..cb37c17cc 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 b6a857905..115431784 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 844d9e47c..0e03df161 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 bf5aad6cb..52ba58254 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 d25ae7476..4f0e833b5 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 cf124de8f..08afdcf5b 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 66c9bb98a..734c2fde2 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 67ad354aa..6b0f27e35 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 39eafb0c3..afc871c08 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 089b67877..bf0a07f68 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 a17db9799..583a22ab7 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 0dcccc8a4..78f0fedd1 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 bbc44aab4..c2edd7deb 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 e1f60d664..8432deaa2 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 fa80c2a34..efa188f01 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 81a196ec6..53c24df27 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 f49d1b10c..b8c26a7be 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 d5a053240..2e725c53e 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 573ec8c30..54ca707d7 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 62ad0b4d3..4484f8bc8 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 5ccdd707d..13ab5552e 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 64d0813cb..34203a6dd 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 87f3ba2f6..6ebaf6a04 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 cd12ea159..0bf7a6cb9 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 17cf60ed1..23a3da0e8 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 64352fb5e..5ec93bbe9 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 73753a70b..84e9a7d29 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 7c4c24916..ee8818c0f 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 188edfcae..f48d0b3af 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 5bd75f486..f704649b7 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 5c277bf08..f2b8973ac 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 f5dcda623..40b51d993 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 5fdd6d647..0033956c9 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 db5c43d95..8f79d7775 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 50fb29324..561328990 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 e147ad2c1..5c14da323 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 cef2058a1..67ce16968 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 b6f1a24de..97fa81a62 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 41a6955cf..92526bc53 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 535cec38c..e1d8cc2fe 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 26d23d396..58ec5f2a1 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 1e9299271..eb649fe22 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 40d6bf457..5a1f16ded 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 4833ab0d0..1c8dd17b6 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 5976ed234..d9d05bb3a 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 4ee5b7973..3d6ef0545 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 7baa1fee9..8eccf0ada 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 1e17c4c48..16447e5f3 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 5925e9f50..3231287d2 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 59fb55433..c38c54728 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 2ebbcd3fe..81123359e 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 b7769fb46..3e910af2c 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 3505d8b84..a1324e358 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 e39803d0b..623fd1caf 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 8c9d93545..cc999d797 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 b1c001bb8..38d5541ae 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 d3b2d274a..4285dd087 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 f28571682..ad40bbbb7 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 d4d765d26..5c7c0a361 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 97fac20ca..3d47e438d 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 58c1a3844..119f0d23a 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 3973f0758..478da0243 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 20c9b19cd..31f5553f8 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 3ab1f0249..216691ae0 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 f1dddd8f1..a1b3a9c98 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 5b07e82f2..28d06e826 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 9c0076bd7..66dc0d04e 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 d008883b7..cd0571b30 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 b7898ee41..87e971712 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 b64308936..95a40ff46 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 14e8ca7c5..d83e37380 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 2fbe69d92..060519ab5 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 7b572b34e..9fec03965 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 3bc743eae..2ca0f06bc 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 911247591..2b4d22b3d 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 d7489336b..0e61281d6 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 5b07307dd..b4ff08612 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 6fa96f183..b366d40da 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 cad8498c3..2fbc91c9a 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 3472b7794..9b945d54c 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 28ea473b6..3eeaef66b 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 207b9e8bf..38e580748 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 8b5c4cb50..36f2dee27 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 805cb08b5..8d3150513 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 d49a74efd..49302e5ed 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 5981d98ff..3f414b7ef 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 4acc357f8..2b3bb74b3 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 57b5218c8..61e4fb2d9 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 678a654fb..d0f9614e7 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 e8af359ba..61febbf99 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 e756503f4..dc90095fb 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 89da1ce7c..7ab4a118d 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 6d17f3189..fbc87e92c 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 4bdc43ad7..35c19442c 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 3f414bfd1..99e81fb85 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 a43b20b02..faaa1bf8a 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 1ba00329e..98959fe76 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 1a34c8cb1..99f780b98 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 01ae64a44..a37630872 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 423db6ce9..09a0b6f1b 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 ed5257c58..895159ce9 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 30c9da492..5fd1adbb2 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 cb46c720d..7b7cd67ee 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 8aa2a7f3b..e125bec70 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 9194df913..add6ce20b 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 8b4d1a276..3d75a03e2 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 1a852eaea..b61524f7a 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 5da5cc912..2ed0e14d7 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 15f2ef360..bf184325e 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 060a09480..225b0a347 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 7b0dd25bd..5915b9f78 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 1cdc0f42d..834f81ed0 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 eee4cb293..5df96e2e6 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 3e10f561d..7b37ad3f8 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 94cae9112..66ef3ac87 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 f6c574544..eaa681d54 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 6f0707638..2d98360b7 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 0d489fc94..8755a39ec 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 4262d36be..af296cc4c 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 61794b096..720b47e1a 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 514cf3e2e..dca389061 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 35f720ff3..c121ff9e7 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 aa21965ee..2c3cc1d4a 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 0f24ffd4f..92eabead1 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 46af39a31..000000000 --- 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 ea75d82bf..000000000 --- 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 7c9c7cc4e..000000000 --- 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 b61362794..000000000 --- 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 1f0e55879..000000000 --- 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 875664640..000000000 --- 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 d1a2e2436..0bb2b22c2 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 0ffd6a034..000000000 --- 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 f2f5b7d36..000000000 --- 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 7af886299..000000000 --- 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 b03ac6523..000000000 --- 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 025d4d7c1..000000000 --- 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 403f8bbfc..000000000 --- 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 20e8d3bf8..000000000 --- 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 4a8ca9100..000000000 --- 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 691056b87..000000000 --- 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 8b5a4bbe6..000000000 --- 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 d6272a6aa..000000000 --- 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 a5cc12e25..000000000 --- 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 9e496471e..4cc962d03 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 bf1bc9924..836bf208f 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 ae940905b..ccb95a789 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 c3ff9e325..ff5a3de98 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 39a02fa9c..9da2f0f3c 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 d37fb0d9a..74a8c8375 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 58844729b..86c612afa 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 9c1511b53..06a1c032e 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 ffb6ec90a..c08d63807 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 6c327f423..ffb4c0ead 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 000000000..150d89ea5 --- /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 5a6ac25b4..727bba580 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 770a8f13c..c66cb78e0 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 000000000..886359882 --- /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 602f61711..9a271521d 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 000000000..9fd22ad09 --- /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 78e75b101..6eacd0232 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 b4d47698a..816133dd4 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 501ce46f6..464adcb17 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 7cb18ba19..ef720f165 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 fc383cdc7..97ef46af1 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 3c9096d1c..e87d86d88 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 8f260c552..a6577b3fc 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 49bb66f49..fc826b3a4 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 3f7e65b26..8f9ac686c 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 a331cd065..9f6a374ee 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 de62b0e61..4969a260e 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 d0ac4f63e..b1a07a300 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 40b508a55..4e926999e 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 61842ebf4..8bd098df1 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 0a812043f..39fd0a162 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 7b50b63bd..8b4c22788 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 3f5a8f11f..ab6b59322 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 3399d98fc..2c1ca09e2 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 e97ea19d9..203f42bd7 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 5d687851d..a92e39f3f 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 2785203e0..ee1440a5c 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 84a70f1da..707be49be 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 382fd64d9..16266ae1b 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 42ac888f3..0d38a4f5b 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 9ea77f2a9..53307f0b9 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 536c8bb2c..c7cd84919 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 1d5725f0f..9b8a5604a 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 4826f08cf..562e5f307 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 b2f0c581a..3af417f06 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 3a90c552e..838038e69 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 7586b058d..3e55232b9 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 7465ef466..ba8445036 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 75904c921..3c3facf3b 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 673808088..6a1a46a77 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 f026191fe..cb11e7476 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 c60869fdf..2b738fc0f 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 aecc10fa5..a3111ca3d 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 6618467a4..9d2f0c63f 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 a6af5d84e..f31b4d5f5 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 7378e2086..2b9000629 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 0492a26b0..cbeb2fe22 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 32561ccd6..fa3c2ac0b 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 d543c4658..ce6f74e4a 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 7a78014e6..76d6342ed 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 3c9d16585..d81311e44 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 f788d3212..4f626db66 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 175bc05fd..421d14a05 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 94eea5fa7..04b1a0ac8 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 78541c35b..d287350d3 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 f22468c2d..1e327efb0 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 d800d8eb8..d72f8e6dd 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 25d192fe1..d183ce43c 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 4798fb5bc..002d8aca8 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 000000000..dca489a28 --- /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 000000000..0e3ec2490 --- /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 c59f5b019..cb81713a4 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 cf857f66c..8587a707f 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 8f520077b..8399639c4 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 7a6a2f8d6..40656a033 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 9e0d353f7..bf0b29d39 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 000000000..2928a48df --- /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 f8b8a9926..435f853ce 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 bfe3f9d6f..1ca19fdca 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 b6fd97e0f..abf1da1b2 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 a5cd423e0..4bf0270a9 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 000000000..df36449fe --- /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 000000000..7864f1ef9 --- /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 61a95097c..415d295b2 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 99fc4a1c1..77347773a 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 bb4473c54..32cce2a94 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 1ed20707e..e7308f935 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 9292790a5..d5c30dfba 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 037aa2ffe..e5e6d4c98 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 a97e82157..bfbeb2436 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 70136be20..adae3512f 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 79dcfdb18..a3a9c63c6 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 ac499b443..0fed3c8d1 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 6f62fb287..85fc4b4c4 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 a801f84d0..d7a53b8ad 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 6d1050acd..edbf77f16 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 039ec3916..8bb97f855 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 fe33552d2..a646d2414 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 8a301109d..67356b2ed 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 2ac117b69..62b353a12 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 ed0fcfa9c..ba5b30576 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 4eb6daa85..9a7a6cebe 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 e80d553db..27410def9 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 7d6d58109..263d0dbe2 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 a282c9e49..1a8759d7d 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 0f6f58aee..e471d4f17 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 87d01b85e..246e2cbb9 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 dc0f83908..dde960e67 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 8dbb39194..30cdd00c5 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 fd57436ea..41c2ee90f 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 ee71c2381..a914aad22 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 468886239..d859ddc7e 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 ba1ca1499..3f5b4a9b4 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 cbb42d956..cb90026b1 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 db6ed62b2..eaf177bed 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 95c11e888..bba274c5a 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 0bd9d4092..ab57f7a72 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 2184ac62c..3b04d4c50 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 000000000..e858fa439 --- /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 ea8349a24..73a28a35c 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 000000000..eaf972de6 --- /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 d62ddface..a34cd01fb 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 c417c8f81..c3c4ca9e7 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 3d801e963..e3db2dd1d 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 40dbd3a16..add89ddb7 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 a9fc14f09..2c4ddc508 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 05fc16b4c..d15827cb7 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 f4ad7a243..54925b539 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 ee1c611fa..48259f815 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 3b494e0e9..d4782c194 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 bf36f2454..8ca4b001b 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 b92452f38..2b4b3c16e 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 a4a0b3274..d24d94eb8 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 1cd4cb49f..787955a6d 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 8e8bb9781..8d14fcd6a 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 fe4672f1f..3e35539c6 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 d45141c0e..cbb95215c 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 5518184da..708b788c7 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 581e65a05..bbb985dbd 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 c11dac244..4e14f78bf 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 a3b9ad43f..62569ff8d 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 92e0f48ed..c827ff84d 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 5854fa927..40d1ebd7b 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 aeba87840..aedad53a3 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 edf55518c..a3f6dde13 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 5910c392c..139957998 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 548b020a3..ace9606d3 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 5d3980940..37b80846f 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 8dcb28aca..4192419fd 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 502e1e78c..51c7f616d 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 09b5b91e5..f259e09e5 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 a3c094c6f..7c6914c08 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 52699b94e..758066f32 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 0dccda379..9faa76a3c 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 c99f5c6fa..bc2080547 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 000000000..85eac980f --- /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 000000000..ee282c2af --- /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 35a56451d..411dc4840 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 dd72fc21d..b44e59a73 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 8ddc0d9c5..1526bec8c 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 bdd5cb1a3..d0cf6daa5 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 0644380fd..202a950f9 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 4f52a3434..e49a5e2e0 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 99b52fdc5..4cb2a0daa 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 77ac39362..20dad9a4f 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 869c82365..830fdfe6b 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 7ec89956f..9d7e6db3e 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 2d5608b8a..bab1302d0 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 323c24c1d..5a8b69b7e 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 9675a8fe1..858c48ad3 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 e88d1c6b3..d26af71f8 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 bdd23920b..3bd2e4ba2 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 096b5be66..7583874b3 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 6fce192d1..4576f8b10 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 e37f0439d..5a4929300 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 eb9404e14..c390be19f 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 6a72a0291..f34a195b8 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 96d655716..4d313572d 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 7e0e0e161..361c24512 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 8b02fc2bb..f601ab8de 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 92ec393ef..e58c8d1ce 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 5628336f5..f50a5dd48 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 e75924a1f..060062de9 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 6b0d007dd..6a4aa324d 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 696963509..7b2543af5 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 d5b2a85dc..ef1907ebc 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 cccbde429..fce0f2b4e 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 a449b48a0..463b71251 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 22b4ca190..7ff5f1825 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 61396fe8f..6c6363072 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 f8f241b5f..b5a526efb 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 e6ff0b8b8..0bdf27a46 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 fb11f2ff6..7570e9864 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 210becd6d..8fe1ba355 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 b7dce5674..496240a78 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 935ed37aa..1a9fb42bf 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 f31180824..2703f7807 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 d7a743a72..2e8597f5c 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 6293e094c..b47f7c3b1 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 6f50623dc..d06d8699f 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 94dc26f07..6ed45ce92 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 b609c3509..ebb7adf95 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 acf7e2b1b..9f465bfe7 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 c7feb946b..0a7668949 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 927eb0c87..687bae492 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 db1b5eb14..a84e27981 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 aa8344b74..3f088ec42 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 14c74e3af..90d5944b7 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 dc9bb9d64..8b127cc83 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 8d96412d4..8e377e44e 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 8c53dab40..8751562e2 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 066b90dc1..0383a2d9b 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 3fe413874..6c4812f8c 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 046709b51..4dfe4a2be 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 b09881d57..51a1ff97f 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 a52560691..6b3308f05 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 4035d3ce6..5faf669b2 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 f006a731e..5c752b7a3 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 4f891256f..9a1788417 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 a3c9a23ed..284fd36d9 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 7a19f9aa8..502fac516 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 04688cb9e..616de2709 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 a4afdeda8..a63df910e 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 ce210e6e8..1a5d6ad1a 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 db5d43c61..07af34334 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 a295a4da7..b8981699e 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 809e39c2d..6160c1670 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 efe83c17a..983a998f0 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 3b7818473..2cf188b01 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 4ea010ab3..2c4fdf86b 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 b49e0e9a5..c51d90b8a 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 3c11b0d01..d5e43edfa 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 e5ad9f340..779b6439e 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 eabbdb754..9f87a6298 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 b93684d5c..94963a656 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 10f9474bf..7c8778f1c 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 78773ba54..6fc027ac3 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 122a9d7b0..c2d386972 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 97a0440ba..13cb860a0 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 4575d0a99..b7d6a1b14 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 4e7f4d045..38355a867 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 e4073aa41..861724442 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 208cf7753..1ea4f0143 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 910c5a179..3e706948f 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 3e99eea63..8a57ebee2 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 3371f5169..7a2ee256a 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 ab12e8be3..d6b3e993e 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 f6483a673..9b0744c0b 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 a837fc98b..66c9e77c8 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 6b761c514..be2799384 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 7cc77bacc..3fb8d3e3c 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 b065154d4..abf1af670 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 17296cc6d..1d9c427e3 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 9476d37a8..324ec0d3e 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 483a49a8d..1c0c65fe2 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 5bc95dc4b..9a208bd9b 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 cda984041..3c3382687 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 f313ee2ca..c6a06ea7b 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 660a79225..4231642a6 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 c482ec469..467ed3f7e 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 47c1a15c6..e5f6078d6 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 7d3966bb9..4da284b20 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 24889ffb0..b3fff1a71 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 407bc3710..64492dda2 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 92c029f11..928bd3d79 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 2cf0d5fae..7ff5df5ad 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 498d2b19a..c733b94e4 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 4e232f63b..f6625d50d 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 43a2b2909..cf3ff1b3e 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 d7f682472..c6d5c486a 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 8fa099d5d..7f2ed5f29 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 d98d89eeb..576f0c193 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 1ddba1261..a5ef407a6 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 35909b400..f4e3bd600 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 5b317e2bd..0b1921e92 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 000000000..acb102a1e --- /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 c2cc17f1c..452826528 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 89353d771..d5653b017 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 0ec0f5bc6..7fffaebb0 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 3b21dad25..ec84fe0cf 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 7515513a8..bcfa133b6 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 a9e14c7f3..ed340aaa9 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 0777eff50..a0fdc3c8e 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 efcefbc10..2c4b5ba15 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 4629e489b..64747f48e 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 000000000..61ab48443 --- /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 23000427d..6e979811e 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 05296b7c0..d3d7def5e 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 f7a579aa4..6bd55b0bd 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 af193467c..de7584fcc 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 a7df25d16..b5c2bf611 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 6ed8c94e8..d19ea1d27 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 8db993596..15e5ff9c5 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 62acb6949..fd5cf1f58 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 cc07e0685..771884b8c 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 919bc33a8..4fb9e8480 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 1f019bac6..0d2f0f625 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 c3cf1add2..c906515d6 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 1bb56fc6e..584842277 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 9f5373365..4dc25157a 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 e2bb5591f..5d41c61e3 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 66421f5ef..4719dcec1 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 bcfbcfc6e..5a8ec18ec 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 93f389cf0..b0816ef19 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 eca37af6d..0459ad5f0 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 02e0fbd10..92d11a598 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 82de81214..f81bcf2a3 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 daaab9d29..29c7b4d12 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 3a447e962..34dc78e70 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 ad98fd778..39d2230d6 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 3d4e8bb49..ccc0e45aa 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 25880d836..f24f4b6c4 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 69fd21af1..c67a1fdbf 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 9a1010c89..cb87f97fa 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 2292a4c41..145a08738 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 60845fbcb..d2900444d 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 b703a6f7b..dd50a8a1f 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 23b24847c..3a20129fc 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 9dc50d978..cc7987c20 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 9edd62937..7ed8fb36e 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 bc24afe51..693ac5cac 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 ee956a08c..4d7157d0a 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 90bb59757..7dd334d66 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 bb32b0921..f5a4fbca1 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 d56776690..d38c1ab1b 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 5687d5fbf..7c8e1c930 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 1ecedc91e..f141536fd 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 05814441c..d5f7a283d 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 56961287a..9663dc0ed 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 cfe346311..c43eb30d8 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 df2d007df..96cb8de3c 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 c1e82b1cc..d76e18767 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 b0cd4dfd3..e56012bf6 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 063048451..6d75575b7 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 99440c145..784596f0a 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 4919302c7..eff119979 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 138e7ea5f..636f3c0d2 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 bf3646c0a..8f3c1cddf 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 c5c9062c7..1c487501b 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 3891a7cad..d6e9bd84a 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 ea7253cc8..2643bffc5 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 c2f929f66..8a4cfaf6b 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 da9810bb2..1092292ab 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 7f4c6953b..50c3d5e44 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 e158c766f..580454089 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 e9007ac37..f24c297d4 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 37f65ba40..e0cf84358 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 432e78a7e..c9fca2ddd 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 8a0381644..80f8f87ee 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 a33a6c2ad..ebc6d3a16 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 9b6f5a363..f1f601c64 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 018b5e522..8c65370ab 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 55f621e87..9f332f496 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 94516387e..2b46e4001 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 9d9597506..81ea550c8 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 a7bca9fe2..d822f57bc 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 23d7eeb29..2d153585e 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 59fe9d0c0..d6be6d848 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 d1124ebc3..d4e047d2d 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 bd7299f9f..d6962b031 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 41c25adea..82122491f 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 f2901533e..cf0d1552f 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 e2768c459..e900332e1 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 f6704ccb6..89480352a 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 3924e101b..1c2004f34 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 dbef78241..8fdd9db9c 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 a86d4215c..a666a41e4 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 3f94a7c8f..ec89c9dcd 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 2e47fcbcb..00514b7e8 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 d7687bf21..ea9b6fe9e 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 02ad68890..632e9f1b3 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 65e7a61fc..6d8d8760c 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 210cc13f9..c8a06bde8 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 8f2e65cf3..b408fd19b 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 18342f0f2..297fc6aa8 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 8f1093b0f..2edac4794 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 57215a443..1ecf00e47 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 7315ecf39..1132557b3 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 a46e0e2ee..5d2bac70e 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 69d2f1d19..3d7f8b685 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 8088d6506..14da5f4a6 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 0007b48c1..7aa603bff 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 645eb87a5..6f99ed24f 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 39738bb91..6e536ea74 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 0751775fe..523026669 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 d2862f8ab..928b5762f 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 a4e00839e..213277d61 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 d1cd9cf23..5de8e7452 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 29fcd7c20..584939eb3 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 c92515154..3fe6c2161 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 870bd9df6..fd750e268 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 1e2a4582f..f0b805183 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 94e8d04bf..1856de141 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 b0cee2d87..82ad704bb 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 107c5ea78..1b9d8b2e1 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 5c1fc2a65..974d95277 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 2bccc4790..d0aba3524 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 91fba3593..7866c65f5 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 09e62790d..8dff4f442 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 2db22f6da..e7b9de670 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 8628b3fce..b3bf6668c 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 af274d9ef..fefb73faa 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 262d201e2..fcdaba6ec 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 9b51ac785..87676399d 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 293ecde40..be03fd257 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 8d9595d3b..8a3222b59 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 d20fd8993..6eef07466 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 2f3c4efca..e82a8c5bd 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 da4c72540..3de5fad9f 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 6dcd9a31e..f5b34919f 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 b1be670b9..d6c198a64 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 63598db3d..6b5ccbc41 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 5468c1976..82ce001bc 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 2810fe19e..a6c88f820 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 b025dc79a..a7706ff6e 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 f47606412..d2cd247e8 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 d2278feef..dbdddb794 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 04291e4df..56bee9d41 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 96122fd36..0447a97f1 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 4056e736e..e112c5e9a 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 ea94b7466..516cd049a 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 427a52f03..5562144a3 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 3c393950e..c5fc2131e 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 153faa5e5..0d6d2c030 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 263ff5abb..816420f69 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 fe55ccab7..d5909007a 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 3f0ae6d8a..9ad86abe3 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 6c6bd7deb..5c6c4780b 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 cf07ae1f3..365903e54 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 2c7188b0b..dde397272 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 cda211d95..68b87575f 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 6a30162c4..b5a32e0bb 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 315357aaa..9612fda08 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 810984674..9523f5101 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 0b103f819..833b69272 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 501772b59..b01ffb969 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 a4b2d218b..7db4ed4cc 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 fabcfb31b..6fc73885f 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 46df00386..508a3cb63 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 7d773bf5c..94abffca2 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 d98b19182..1faad7501 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 6fa477c6d..b0de03e41 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 4a1823897..073b08115 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 3f391eadc..569d65464 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 e60fdedcf..729411138 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 6e80ba713..8657de53f 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 357adc7c8..0954b51ae 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 0bc4fedeb..5ca763fd9 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 fb9f5319b..4d0464f7c 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 bdaf07682..a21a4505e 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 af56d81f2..0a7b8d477 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 9f42b8ad7..c1dbfd41f 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 2dc30e039..a0610004d 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 5853f5f7e..2352f42f7 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 08c10fd9f..3c24cc17f 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 7ecb255b7..0b3e2fa3a 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 fc80d1829..7c56c4a52 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 9e2c12570..bbdaef7ee 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 000000000..b03168a6b --- /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 000000000..abe3e727d --- /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 c40a8767a..e2c629ddc 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 000000000..066961fef --- /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 54e6f80a1..5b6fee5a8 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 000000000..a6e109eb4 --- /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 0ff6eec22..4882f15fc 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 000000000..b9ee7f61c --- /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 000000000..f6da0be7a --- /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 000000000..518a3c6f3 --- /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 efd8e787c..ae2b90cc7 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 5063f3427..557c0b383 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 000000000..6ef3b2119 --- /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 000000000..678b26f24 --- /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 000000000..e9b7097cf --- /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 60e069e46..8074933d3 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 0bd1ceec2..565a60862 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 000000000..95868b19f --- /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 000000000..48b10c129 --- /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 000000000..cc1294b27 --- /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 000000000..57f97a500 --- /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 000000000..8400c50d2 --- /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 000000000..ec4a93d4b --- /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 000000000..96a18f520 --- /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 000000000..f30fc70b3 --- /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 000000000..3a5dfa2e5 --- /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 0f94fa8ac..e6b986b9e 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 000000000..a60a9d9ef --- /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 000000000..efc1ce09d --- /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 000000000..74cef2daf --- /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 000000000..921987541 --- /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 a98bcd23d..e44ed5e8f 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 2afb0bb41..536be7973 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 20887c96b..a20cd4777 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 f58a4cf7d..e362ede01 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 dc9ac38ea..e71edcbbe 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 cb22c26ba..886722105 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 39f7bef06..39d8c4be9 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 674d72bb0..4c0b38be2 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 fd936867a..7046609cb 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 675789e6f..d5b55b61a 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 c4609ba93..4fc3a33fb 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 7255da024..3cfca47c8 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 6ca46f02d..6d443a2ea 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 f6e9cfb11..212a126c0 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 9202392cb..fe6c4f7a9 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 b5c40011e..1d5f3e99d 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 b90ade333..1b057da44 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 0266f5ba4..19b747937 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 2ca733f3a..bf577249c 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 5221b9947..6e5d4df61 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 000000000..521c0dadd --- /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 000000000..c73cec34b --- /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 000000000..ff745026f --- /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 000000000..8fe3954c2 --- /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 000000000..8ac830115 --- /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 000000000..0172dc0e0 --- /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 b80e2238d..d8e12849b 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 000000000..b5ec2df1a --- /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 000000000..97af02c5b --- /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 000000000..76c8b72b6 --- /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 000000000..1444daffd --- /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 000000000..c08d8edef --- /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 000000000..5029a922e --- /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 000000000..048224352 --- /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 000000000..51e91a706 --- /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 000000000..dd5b77b6e --- /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 000000000..250981650 --- /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 000000000..931211088 --- /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 000000000..6d5910ad7 --- /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 000000000..4eda0ea28 --- /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 000000000..a3b326514 --- /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 000000000..223dcf98c --- /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 000000000..0f5b326a4 --- /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 000000000..9aaaa1dbb --- /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 000000000..e9ff8dd5b --- /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 000000000..0977f44b3 --- /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 000000000..ab925260c --- /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 000000000..db201a94b --- /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 f5cadf3be..ec704d356 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 5351028e0..ccef964d4 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 000000000..a57fcf79d --- /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 000000000..449043ce5 --- /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 000000000..83da81ef6 --- /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 000000000..1ae9543a6 --- /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 000000000..47775b850 --- /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 dc224815d..273a1da62 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 000000000..17f64c17f --- /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 12b1f07fa..685c17d86 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 000000000..1f88d0563 --- /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 5df44323a..6452e1c65 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 000000000..39da52a39 --- /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 39af2cc8f..09f1a3d59 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 fe7007f79..fe1159b11 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 000000000..701a67ef2 --- /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 f324c42c0..46c0b52ee 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 000000000..3cfc25a46 --- /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 000000000..688bac475 --- /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 ce73d51e5..8dccd3219 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 c9c3c1c59..492558854 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 888b64c42..0d5056230 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 8c19df501..81cdbd681 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 000000000..3fa99b925 --- /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 000000000..2046d581f --- /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 000000000..01249d3d7 --- /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 8bba32709..2e3aba365 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 4de756818..01eb3b67e 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 000000000..630df6e4d --- /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 000000000..ab98703e2 --- /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 000000000..734e9f269 --- /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 000000000..f7409a228 --- /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 000000000..877114e2a --- /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 5b54c8be7..96280f264 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 24e057707..00a51c43f 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 962932c9a..6a430bb86 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 260782dbf..d938a21e5 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 a9ff7b419..b5c065a61 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 000000000..0da0917b9 --- /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 6f4c21bc6..c46b4496e 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 000000000..b3135f049 --- /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 7e3026190..c71dae98e 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 cb0561e8d..6c76f66d4 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 000000000..521c0dadd --- /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 000000000..cb54909bd --- /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 000000000..29a4cb091 --- /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 3bcb46024..b08564336 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 000000000..c66cb78e0 --- /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 000000000..fa94a6a43 --- /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 000000000..9a271521d --- /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 000000000..0977f44b3 --- /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