Compare commits

...

8 Commits

Author SHA1 Message Date
6858d7e72f Remove nonfunctional LibreTranslate servers 2023-09-30 12:54:31 -04:00
William Casarin
476f52562a nostrdb: fix profiles not updating
Send relay pool events to nostrdb as well

Whenever we send events to relays, make sure we send them to nostrdb
at the same time.

Changelog-Fixed: Fix profile not updating
2023-09-24 17:07:09 -07:00
William Casarin
f591ad2dff ndb: add process_client_event helper
This is a quick helper for the new client event processing functionality
2023-09-24 17:06:35 -07:00
William Casarin
dacade299d ndb: bump nostrdb to support client->relay note processing 2023-09-24 17:06:04 -07:00
Suhail Saqan
cdacbcfdca util: add ImageResizer to change size of images 2023-09-24 11:58:16 -07:00
Daniel D’Aquino
41e036cff2 Remove toolbar background from profile view for better looks
Device: iPhone 13 mini (Physical device)
iOS: iOS 17.0.1
Remarks: Some entitlements removed locally to be able to build to device without access to development certificate

Steps
-----

1. Go to the home timeline view.
2. Click on a profile on any post
3. Swipe back to the home timeline view (Do not press "back" button)
4. Click on that same profile again
5. Scroll down the profile
6. Make sure that toolbar looks good (Does not have a white background)

Results: Swiping back from profile does not cause any issues. View layout of the custom navbar looks good

Changelog-Fixed: Fix small graphical toolbar bug when scrolling profiles
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Signed-off-by: William Casarin <jb55@jb55.com>
2023-09-24 11:55:31 -07:00
eb901a4d84 Fix localization issues and export strings for translation
Changelog-Fixed: Fix localization issues and export strings for translation
Signed-off-by: Terry Yiu <git@tyiu.xyz>
Signed-off-by: William Casarin <jb55@jb55.com>
2023-09-24 11:33:51 -07:00
William Casarin
9f15688699 v1.6 (19) 2023-09-24 11:33:40 -07:00
20 changed files with 507 additions and 153 deletions

View File

@@ -415,6 +415,7 @@
9609F058296E220800069BF3 /* BannerImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9609F057296E220800069BF3 /* BannerImageView.swift */; };
9C83F89329A937B900136C08 /* TextViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83F89229A937B900136C08 /* TextViewWrapper.swift */; };
9CA876E229A00CEA0003B9A3 /* AttachMediaUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CA876E129A00CE90003B9A3 /* AttachMediaUtility.swift */; };
BA37598A2ABCCDE40018D73B /* ImageResizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA3759892ABCCDE30018D73B /* ImageResizer.swift */; };
BA4AB0AE2A63B9270070A32A /* AddEmojiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AB0AD2A63B9270070A32A /* AddEmojiView.swift */; };
BA4AB0B02A63B94D0070A32A /* EmojiListItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AB0AF2A63B94D0070A32A /* EmojiListItemView.swift */; };
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA693073295D649800ADDB87 /* UserSettingsStore.swift */; };
@@ -1094,6 +1095,7 @@
9609F057296E220800069BF3 /* BannerImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerImageView.swift; sourceTree = "<group>"; };
9C83F89229A937B900136C08 /* TextViewWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewWrapper.swift; sourceTree = "<group>"; };
9CA876E129A00CE90003B9A3 /* AttachMediaUtility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachMediaUtility.swift; sourceTree = "<group>"; };
BA3759892ABCCDE30018D73B /* ImageResizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageResizer.swift; sourceTree = "<group>"; };
BA4AB0AD2A63B9270070A32A /* AddEmojiView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEmojiView.swift; sourceTree = "<group>"; };
BA4AB0AF2A63B94D0070A32A /* EmojiListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiListItemView.swift; sourceTree = "<group>"; };
BA693073295D649800ADDB87 /* UserSettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsStore.swift; sourceTree = "<group>"; };
@@ -1239,6 +1241,7 @@
4C0A3F8D280F63FF000448DE /* Models */ = {
isa = PBXGroup;
children = (
BA3759882ABCCDE30018D73B /* Camera */,
4C190F1E2A535FC200027FD5 /* Zaps */,
4C54AA0829A55416003E4487 /* Notifications */,
3AA247FC297E3CFF0090C62D /* RepostsModel.swift */,
@@ -2251,6 +2254,14 @@
path = Extensions;
sourceTree = "<group>";
};
BA3759882ABCCDE30018D73B /* Camera */ = {
isa = PBXGroup;
children = (
BA3759892ABCCDE30018D73B /* ImageResizer.swift */,
);
path = Camera;
sourceTree = "<group>";
};
F71694E82A66221E001F4053 /* Onboarding */ = {
isa = PBXGroup;
children = (
@@ -2794,6 +2805,7 @@
4C3BEFDA281DCA1400B3DE84 /* LikeCounter.swift in Sources */,
4C32B9502A9AD44700DC3548 /* FlatBufferBuilder.swift in Sources */,
50A60D142A28BEEE00186190 /* RelayLog.swift in Sources */,
BA37598A2ABCCDE40018D73B /* ImageResizer.swift in Sources */,
4CB88389296AF99A00DC99E7 /* EventDetailBar.swift in Sources */,
4C32B9512A9AD44700DC3548 /* FlatbuffersErrors.swift in Sources */,
4CE8794E2996B16A00F758CC /* RelayToggle.swift in Sources */,
@@ -3175,7 +3187,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 18;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\"";
DEVELOPMENT_TEAM = XK7H4JAB3D;
ENABLE_PREVIEWS = YES;
@@ -3224,7 +3236,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 18;
CURRENT_PROJECT_VERSION = 19;
DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\"";
DEVELOPMENT_TEAM = XK7H4JAB3D;
ENABLE_PREVIEWS = YES;

View File

@@ -7,30 +7,49 @@
import SwiftUI
enum StatusDuration: String, CaseIterable {
case never = "Never"
case thirty_mins = "30 Minutes"
case hour = "1 Hour"
case four_hours = "4 Hours"
case day = "1 Day"
case week = "1 Week"
enum StatusDuration: CustomStringConvertible, CaseIterable {
case never
case thirty_mins
case hour
case four_hours
case day
case week
var expiration: Date? {
var timeInterval: TimeInterval? {
switch self {
case .never:
return nil
case .thirty_mins:
return Date.now.addingTimeInterval(60 * 30)
return 60 * 30
case .hour:
return Date.now.addingTimeInterval(60 * 60)
return 60 * 60
case .four_hours:
return Date.now.addingTimeInterval(60 * 60 * 4)
return 60 * 60 * 4
case .day:
return Date.now.addingTimeInterval(60 * 60 * 24)
return 60 * 60 * 24
case .week:
return Date.now.addingTimeInterval(60 * 60 * 24 * 7)
return 60 * 60 * 24 * 7
}
}
var expiration: Date? {
guard let timeInterval else {
return nil
}
return Date.now.addingTimeInterval(timeInterval)
}
var description: String {
guard let timeInterval else {
return NSLocalizedString("Never", comment: "Profile status duration setting of never expiring.")
}
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.allowedUnits = [.minute, .hour, .day, .weekOfMonth]
return formatter.string(from: timeInterval) ?? "\(timeInterval) seconds"
}
}
struct UserStatusSheet: View {
@@ -68,43 +87,43 @@ struct UserStatusSheet: View {
var body: some View {
VStack(alignment: .leading, spacing: 20) {
Text("Set Status")
Text("Set Status", comment: "Title of view that allows the user to set their profile status (e.g. working, studying, coding)")
.font(.largeTitle)
TextField(text: status_binding, label: {
Text("📋 Working")
Text("📋 Working", comment: "Placeholder as an example of what the user could set as their profile status.")
})
HStack {
Image("link")
TextField(text: url_binding, label: {
Text("https://example.com")
Text("https://example.com", comment: "Placeholder as an example of what the user could set so that the link is opened when the status is tapped.")
})
}
HStack {
Text("Clear status")
Text("Clear status", comment: "Label to prompt user to select an expiration time for the profile status to clear.")
Spacer()
Picker("Duration", selection: $duration) {
Picker(NSLocalizedString("Duration", comment: "Label for profile status expiration duration picker."), selection: $duration) {
ForEach(StatusDuration.allCases, id: \.self) { d in
Text("\(d.rawValue)")
Text(verbatim: d.description)
.tag(d)
}
}
}
Toggle(isOn: $status.playing_enabled, label: {
Text("Broadcast music playing on Apple Music")
Text("Broadcast music playing on Apple Music", comment: "Toggle to enable or disable broadcasting what music is being played on Apple Music in their profile status.")
})
HStack(alignment: .center) {
Button(action: {
dismiss()
}, label: {
Text("Cancel")
Text("Cancel", comment: "Cancel button text for dismissing profile status settings view.")
})
Spacer()
@@ -121,7 +140,7 @@ struct UserStatusSheet: View {
dismiss()
}, label: {
Text("Save")
Text("Save", comment: "Save button text for saving profile status settings.")
})
.buttonStyle(GradientButtonStyle())
}

View File

@@ -0,0 +1,40 @@
//
// ImageResizer.swift
// damus
//
// Created by Suhail Saqan on 8/5/23.
//
import Foundation
import UIKit
public enum ImageResizingError: Error {
case cannotRetrieveFromURL
case cannotRetrieveFromData
}
public struct ImageResizer {
public var targetWidth: CGFloat
public init(targetWidth: CGFloat) {
self.targetWidth = targetWidth
}
public func resize(at url: URL) -> UIImage? {
guard let image = UIImage(contentsOfFile: url.path) else {
return nil
}
return self.resize(image: image)
}
public func resize(image: UIImage) -> UIImage {
let originalSize = image.size
let targetSize = CGSize(width: targetWidth, height: targetWidth*originalSize.height/originalSize.width)
let renderer = UIGraphicsImageRenderer(size: targetSize)
return renderer.image { (context) in
image.draw(in: CGRect(origin: .zero, size: targetSize))
}
}
}

View File

@@ -28,16 +28,10 @@ enum LibreTranslateServer: String, CaseIterable, Identifiable, StringCodable {
self = libreTranslateServer
}
case argosopentech
case terraprint
case custom
var model: Model {
switch self {
case .argosopentech:
return .init(tag: self.rawValue, displayName: "translate.argosopentech.com", url: "https://translate.argosopentech.com")
case .terraprint:
return .init(tag: self.rawValue, displayName: "translate.terraprint.co", url: "https://translate.terraprint.co")
case .custom:
return .init(tag: self.rawValue, displayName: NSLocalizedString("Custom", comment: "Dropdown option for selecting a custom translation server."), url: nil)
}

View File

@@ -221,7 +221,7 @@ class UserSettingsStore: ObservableObject {
}
}
@StringSetting(key: "libretranslate_server", default_value: .terraprint)
@StringSetting(key: "libretranslate_server", default_value: .custom)
var libretranslate_server: LibreTranslateServer
@Setting(key: "libretranslate_url", default_value: "")

View File

@@ -212,9 +212,19 @@ class RelayPool {
print("queueing request for \(relay)")
request_queue.append(QueuedRequest(req: r, relay: relay, skip_ephemeral: skip_ephemeral))
}
func send_raw(_ req: NostrRequestType, to: [String]? = nil, skip_ephemeral: Bool = true) {
let relays = to.map{ get_relays($0) } ?? self.relays
// send to local relay (nostrdb)
switch req {
case .typical(let r):
if let rstr = make_nostr_req(r) {
ndb.process_client_event(rstr)
}
case .custom(let string):
ndb.process_client_event(string)
}
for relay in relays {
if req.is_read && !(relay.descriptor.info.read ?? true) {

View File

@@ -22,7 +22,7 @@ struct GradientFollowButton: View {
Button(action: {
follow_state = perform_follow_btn_action(follow_state, target: target)
}) {
Text("\(follow_btn_txt(follow_state, follows_you: follows_you))")
Text(follow_btn_txt(follow_state, follows_you: follows_you))
.foregroundColor(follow_state == .unfollows ? .white : grayTextColor)
.font(.callout)
.fontWeight(.medium)

View File

@@ -40,7 +40,7 @@ struct FollowHashtagView: View {
HStack {
SingleCharacterAvatar(character: "#")
Text("#\(hashtag.hashtag)")
Text(verbatim: "#\(hashtag.hashtag)")
.bold()
}
.onTapGesture {

View File

@@ -476,6 +476,7 @@ struct ProfileView: View {
customNavbar
}
}
.toolbarBackground(.hidden)
.onReceive(handle_notify(.switched_timeline)) { _ in
dismiss()
}

View File

@@ -45,7 +45,7 @@ struct RelayConfigView: View {
if recommended.count > 0 {
VStack {
Text("Recommended relays")
Text("Recommended relays", comment: "Title for view of recommended relays.")
.foregroundStyle(DamusLightGradient.gradient)
.padding(10)
.background {

View File

@@ -13,7 +13,7 @@ struct FailedRelayImage: View {
var body: some View {
let abbrv = String(url?.host()?.first?.uppercased() ?? "R")
Text("\(abbrv)")
Text(abbrv)
.font(.system(size: 40, weight: .bold))
}
}

View File

@@ -13,7 +13,7 @@ struct RelayStatusView: View {
var body: some View {
Group {
if connection.isConnecting {
Text("Connecting")
Text("Connecting", comment: "Relay status label that indicates a relay is connecting.")
.font(.caption)
.frame(height: 20)
.padding(.horizontal, 10)
@@ -25,7 +25,7 @@ struct RelayStatusView: View {
.stroke(DamusColors.warningBorder, lineWidth: 1)
)
} else if connection.isConnected {
Text("Online")
Text("Online", comment: "Relay status label that indicates a relay is connected.")
.font(.caption)
.frame(height: 20)
.padding(.horizontal, 10)
@@ -37,7 +37,7 @@ struct RelayStatusView: View {
.stroke(DamusColors.successBorder, lineWidth: 1)
)
} else {
Text("Error")
Text("Error", comment: "Relay status label that indicates a relay had an error when connecting")
.font(.caption)
.frame(height: 20)
.padding(.horizontal, 10)

View File

@@ -24,10 +24,8 @@ struct AppearanceSettingsView: View {
var FontSize: some View {
VStack(alignment: .leading) {
Slider(value: $settings.font_size, in: 0.5...2.0, step: 0.1) {
Text("Font Size")
}
.padding()
Slider(value: $settings.font_size, in: 0.5...2.0, step: 0.1)
.padding()
// Sample text to show how the font size would look
ResizedEventPreview(damus_state: damus_state, settings: settings)
@@ -37,7 +35,7 @@ struct AppearanceSettingsView: View {
var body: some View {
Form {
Section("Font Size") {
Section(NSLocalizedString("Font Size", comment: "Section label for font size settings.")) {
FontSize
}
@@ -49,7 +47,7 @@ struct AppearanceSettingsView: View {
.toggleStyle(.switch)
}
Section(header: Text("User Statuses")) {
Section(header: Text("User Statuses", comment: "Section header for user profile status settings.")) {
Toggle(NSLocalizedString("Show general statuses", comment: "Settings toggle for enabling general user statuses"), isOn: $settings.show_general_statuses)
.toggleStyle(.switch)

View File

@@ -2,7 +2,7 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 http://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd">
<file original="damus/en-US.lproj/InfoPlist.strings" source-language="en-US" target-language="en-US" datatype="plaintext">
<header>
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="14.3.1" build-num="14E300c"/>
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="15.0" build-num="15A240d"/>
</header>
<body>
<trans-unit id="CFBundleDisplayName" xml:space="preserve">
@@ -15,6 +15,11 @@
<target>damus</target>
<note>Bundle name</note>
</trans-unit>
<trans-unit id="NSAppleMusicUsageDescription" xml:space="preserve">
<source>Damus needs access to your media library for playback statuses</source>
<target>Damus needs access to your media library for playback statuses</target>
<note>Privacy - Media Library Usage Description</note>
</trans-unit>
<trans-unit id="NSCameraUsageDescription" xml:space="preserve">
<source>Damus needs access to your camera if you want to upload photos from it</source>
<target>Damus needs access to your camera if you want to upload photos from it</target>
@@ -39,15 +44,15 @@
</file>
<file original="damus/en-US.lproj/Localizable.strings" source-language="en-US" target-language="en-US" datatype="plaintext">
<header>
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="14.3.1" build-num="14E300c"/>
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="15.0" build-num="15A240d"/>
</header>
<body>
<trans-unit id="%@ %@" xml:space="preserve">
<source>%@ %@</source>
<target>%@ %@</target>
<note>Sentence composed of 2 variables to describe how many imports were performed from loading a NostrScript. In source English, the first variable is the number of imports, and the second variable is 'Import' or 'Imports'.
Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.
Sentence composed of 2 variables to describe how many people are following a user. In source English, the first variable is the number of followers, and the second variable is 'Follower' or 'Followers'.</note>
<note>Sentence composed of 2 variables to describe how many people are following a user. In source English, the first variable is the number of followers, and the second variable is 'Follower' or 'Followers'.
Sentence composed of 2 variables to describe how many imports were performed from loading a NostrScript. In source English, the first variable is the number of imports, and the second variable is 'Import' or 'Imports'.
Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.</note>
</trans-unit>
<trans-unit id="%@ has been muted" xml:space="preserve">
<source>%@ has been muted</source>
@@ -137,13 +142,19 @@ Sentence composed of 2 variables to describe how many people are following a use
<trans-unit id="Add" xml:space="preserve">
<source>Add</source>
<target>Add</target>
<note>Button to confirm adding user inputted relay.</note>
<note>Button to add relay server to list.
Button to confirm adding user inputted emoji.</note>
</trans-unit>
<trans-unit id="Add Bookmark" xml:space="preserve">
<source>Add Bookmark</source>
<target>Add Bookmark</target>
<note>Button text to add bookmark to a note.</note>
</trans-unit>
<trans-unit id="Add Emoji" xml:space="preserve">
<source>Add Emoji</source>
<target>Add Emoji</target>
<note>Label for section for adding an emoji to the reactions list.</note>
</trans-unit>
<trans-unit id="Add all" xml:space="preserve">
<source>Add all</source>
<target>Add all</target>
@@ -154,6 +165,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Add bookmark</target>
<note>Context menu option for adding a note bookmark.</note>
</trans-unit>
<trans-unit id="Add relay" xml:space="preserve">
<source>Add relay</source>
<target>Add relay</target>
<note>Title text to indicate user to an add a relay.</note>
</trans-unit>
<trans-unit id="Additional information" xml:space="preserve">
<source>Additional information</source>
<target>Additional information</target>
@@ -206,6 +222,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<note>Navigation title for text and appearance settings.
Section header for text and appearance settings</note>
</trans-unit>
<trans-unit id="Appearance and filters" xml:space="preserve">
<source>Appearance and filters</source>
<target>Appearance and filters</target>
<note>Section header for text, appearance, and content filter settings</note>
</trans-unit>
<trans-unit id="Are you lost?" xml:space="preserve">
<source>Are you lost?</source>
<target>Are you lost?</target>
@@ -283,6 +304,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<note>Button to broadcast note to all your relays
Context menu option for broadcasting the user's note to all of the user's connected relay servers.</note>
</trans-unit>
<trans-unit id="Broadcast music playing on Apple Music" xml:space="preserve">
<source>Broadcast music playing on Apple Music</source>
<target>Broadcast music playing on Apple Music</target>
<note>Toggle to enable or disable broadcasting what music is being played on Apple Music in their profile status.</note>
</trans-unit>
<trans-unit id="Cancel" xml:space="preserve">
<source>Cancel</source>
<target>Cancel</target>
@@ -290,7 +316,7 @@ Sentence composed of 2 variables to describe how many people are following a use
Button to cancel a repost.
Button to cancel out of alert that creates a new mutelist.
Button to cancel out of posting a note.
Button to cancel out of view adding user inputted relay.
Button to cancel out of view adding user inputted emoji.
Button to cancel the upload.
Cancel deleting bookmarks.
Cancel deleting the user.
@@ -312,30 +338,36 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Clear Cache</target>
<note>Button to clear image cache.</note>
</trans-unit>
<trans-unit id="Connect" xml:space="preserve">
<source>Connect</source>
<target>Connect</target>
<note>Button to connect to recommended relay server.</note>
<trans-unit id="Clear status" xml:space="preserve">
<source>Clear status</source>
<target>Clear status</target>
<note>Label to prompt user to select an expiration time for the profile status to clear.</note>
</trans-unit>
<trans-unit id="Connect To Relay" xml:space="preserve">
<source>Connect To Relay</source>
<target>Connect To Relay</target>
<note>Label for section for adding a relay server.</note>
<note>Button to connect to the relay.</note>
</trans-unit>
<trans-unit id="Connected Relays" xml:space="preserve">
<source>Connected Relays</source>
<target>Connected Relays</target>
<note>Section title for relay servers that are connected.</note>
<trans-unit id="Connecting" xml:space="preserve">
<source>Connecting</source>
<target>Connecting</target>
<note>Relay status label that indicates a relay is connecting.</note>
</trans-unit>
<trans-unit id="Contact" xml:space="preserve">
<source>Contact</source>
<target>Contact</target>
<note>Label to display relay contact information.</note>
</trans-unit>
<trans-unit id="Content filters" xml:space="preserve">
<source>Content filters</source>
<target>Content filters</target>
<note>Section title for content filtering/moderation configuration.</note>
</trans-unit>
<trans-unit id="Continue" xml:space="preserve">
<source>Continue</source>
<target>Continue</target>
<note>Continue with bookmarks.
<note>Button to dismiss suggested users view and continue to the main app
Continue with bookmarks.
Continue with deleting the user.</note>
</trans-unit>
<trans-unit id="Copied" xml:space="preserve">
@@ -346,7 +378,9 @@ Sentence composed of 2 variables to describe how many people are following a use
<trans-unit id="Copy" xml:space="preserve">
<source>Copy</source>
<target>Copy</target>
<note>Button to copy a relay server address.</note>
<note>Button to copy a relay server address.
Button to copy an emoji reaction
Context menu option for copying the version of damus.</note>
</trans-unit>
<trans-unit id="Copy Account ID" xml:space="preserve">
<source>Copy Account ID</source>
@@ -521,7 +555,17 @@ Sentence composed of 2 variables to describe how many people are following a use
<trans-unit id="Done" xml:space="preserve">
<source>Done</source>
<target>Done</target>
<note>Button that, when tapped, will finish adding a different user's relays to your relay by hiding the + buttons next to the relays.</note>
<note>Button to dismiss wallet selection view for paying Lightning invoice.</note>
</trans-unit>
<trans-unit id="Duplicate relay" xml:space="preserve">
<source>Duplicate relay</source>
<target>Duplicate relay</target>
<note>Title of the duplicate relay error message.</note>
</trans-unit>
<trans-unit id="Duration" xml:space="preserve">
<source>Duration</source>
<target>Duration</target>
<note>Label for profile status expiration duration picker.</note>
</trans-unit>
<trans-unit id="EULA" xml:space="preserve">
<source>EULA</source>
@@ -538,6 +582,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Edit</target>
<note>Button to edit user's profile.</note>
</trans-unit>
<trans-unit id="Emoji Reactions" xml:space="preserve">
<source>Emoji Reactions</source>
<target>Emoji Reactions</target>
<note>Section title for emoji reactions that are currently added.</note>
</trans-unit>
<trans-unit id="Encrypted" xml:space="preserve">
<source>Encrypted</source>
<target>Encrypted</target>
@@ -548,6 +597,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Enter your account key</target>
<note>Prompt for user to enter an account key to login.</note>
</trans-unit>
<trans-unit id="Error" xml:space="preserve">
<source>Error</source>
<target>Error</target>
<note>Relay status label that indicates a relay had an error when connecting</note>
</trans-unit>
<trans-unit id="Error fetching lightning invoice" xml:space="preserve">
<source>Error fetching lightning invoice</source>
<target>Error fetching lightning invoice</target>
@@ -588,6 +642,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Follow</target>
<note>Button to follow a user.</note>
</trans-unit>
<trans-unit id="Follow All" xml:space="preserve">
<source>Follow All</source>
<target>Follow All</target>
<note>Button to follow all users in this section</note>
</trans-unit>
<trans-unit id="Follow Back" xml:space="preserve">
<source>Follow Back</source>
<target>Follow Back</target>
@@ -643,6 +702,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Follows you</target>
<note>Text to indicate that a user is following your profile.</note>
</trans-unit>
<trans-unit id="Font Size" xml:space="preserve">
<source>Font Size</source>
<target>Font Size</target>
<note>Section label for font size settings.</note>
</trans-unit>
<trans-unit id="Free" xml:space="preserve">
<source>Free</source>
<target>Free</target>
@@ -658,6 +722,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Get API Key with BTC/Lightning</target>
<note>Button to navigate to nokyctranslate website to get a translation API key.</note>
</trans-unit>
<trans-unit id="Hashtags" xml:space="preserve">
<source>Hashtags</source>
<target>Hashtags</target>
<note>Label for filter for seeing only hashtag follows.</note>
</trans-unit>
<trans-unit id="Help build the future of decentralized communication on the web." xml:space="preserve">
<source>Help build the future of decentralized communication on the web.</source>
<target>Help build the future of decentralized communication on the web.</target>
@@ -673,6 +742,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Hide all 🤙's</target>
<note>Section footer describing OnlyZaps mode</note>
</trans-unit>
<trans-unit id="Hide notes with #nsfw tags" xml:space="preserve">
<source>Hide notes with #nsfw tags</source>
<target>Hide notes with #nsfw tags</target>
<note>Setting to hide notes with the #nsfw (not safe for work) tags</note>
</trans-unit>
<trans-unit id="Home" xml:space="preserve">
<source>Home</source>
<target>Home</target>
@@ -861,6 +935,16 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>Muted Users</target>
<note>Navigation title of view to see list of muted users.</note>
</trans-unit>
<trans-unit id="My Relays" xml:space="preserve">
<source>My Relays</source>
<target>My Relays</target>
<note>Section title for relay servers that the user is connected to.</note>
</trans-unit>
<trans-unit id="Never" xml:space="preserve">
<source>Never</source>
<target>Never</target>
<note>Profile status duration setting of never expiring.</note>
</trans-unit>
<trans-unit id="New encrypted direct message" xml:space="preserve">
<source>New encrypted direct message</source>
<target>New encrypted direct message</target>
@@ -881,6 +965,11 @@ Sentence composed of 2 variables to describe how many people are following a use
<target>No data available</target>
<note>Text indicating that there is no data available to show for specific metadata about a relay server.</note>
</trans-unit>
<trans-unit id="No logs to display" xml:space="preserve">
<source>No logs to display</source>
<target>No logs to display</target>
<note>Label to indicate that there are no developer mode logs available to be displayed on the screen</note>
</trans-unit>
<trans-unit id="No mute list found, create a new one? This will overwrite any previous mute lists." xml:space="preserve">
<source>No mute list found, create a new one? This will overwrite any previous mute lists.</source>
<target>No mute list found, create a new one? This will overwrite any previous mute lists.</target>
@@ -939,14 +1028,19 @@ Sentence composed of 2 variables to describe how many people are following a use
<trans-unit id="Notes" xml:space="preserve">
<source>Notes</source>
<target>Notes</target>
<note>Label for filter for seeing only notes (instead of notes and replies).
Label for filter for seeing only your notes (instead of notes and replies).</note>
<note>Label for filter for seeing only your notes (instead of notes and replies).
Label for filter for seeing only notes (instead of notes and replies).</note>
</trans-unit>
<trans-unit id="Notes &amp; Replies" xml:space="preserve">
<source>Notes &amp; Replies</source>
<target>Notes &amp; Replies</target>
<note>Label for filter for seeing notes and replies (instead of only notes).
Label for filter for seeing your notes and replies (instead of only your notes).</note>
<note>Label for filter for seeing your notes and replies (instead of only your notes).
Label for filter for seeing notes and replies (instead of only notes).</note>
</trans-unit>
<trans-unit id="Notes with the #nsfw tag usually contains adult content or other &quot;Not safe for work&quot; content" xml:space="preserve">
<source>Notes with the #nsfw tag usually contains adult content or other "Not safe for work" content</source>
<target>Notes with the #nsfw tag usually contains adult content or other "Not safe for work" content</target>
<note>Section footer clarifying what #nsfw (not safe for work) tags mean</note>
</trans-unit>
<trans-unit id="Nothing to see here. Check back later!" xml:space="preserve">
<source>Nothing to see here. Check back later!</source>
@@ -979,6 +1073,11 @@ Label for filter for seeing your notes and replies (instead of only your notes).
<target>Ok</target>
<note>Button to dismiss the alert.</note>
</trans-unit>
<trans-unit id="Online" xml:space="preserve">
<source>Online</source>
<target>Online</target>
<note>Relay status label that indicates a relay is connected.</note>
</trans-unit>
<trans-unit id="Only you can see this message and who sent it." xml:space="preserve">
<source>Only you can see this message and who sent it.</source>
<target>Only you can see this message and who sent it.</target>
@@ -1024,6 +1123,11 @@ Label for filter for seeing your notes and replies (instead of only your notes).
<target>Pay the Lightning invoice</target>
<note>Navigation bar title for view to pay Lightning invoice.</note>
</trans-unit>
<trans-unit id="People" xml:space="preserve">
<source>People</source>
<target>People</target>
<note>Label for filter for seeing only people follows.</note>
</trans-unit>
<trans-unit id="Permanently Delete Account" xml:space="preserve">
<source>Permanently Delete Account</source>
<target>Permanently Delete Account</target>
@@ -1118,12 +1222,19 @@ Label for filter for seeing your notes and replies (instead of only your notes).
<trans-unit id="Reactions" xml:space="preserve">
<source>Reactions</source>
<target>Reactions</target>
<note>Navigation bar title for Reactions view.</note>
<note>Navigation bar title for Reactions view.
Section header for reactions settings
Title of emoji reactions view</note>
</trans-unit>
<trans-unit id="Recommended Relays" xml:space="preserve">
<source>Recommended Relays</source>
<target>Recommended Relays</target>
<note>Section title for recommend relay servers that could be added as part of configuration</note>
<trans-unit id="Recommended Emojis" xml:space="preserve">
<source>Recommended Emojis</source>
<target>Recommended Emojis</target>
<note>Section title for recommend emojis</note>
</trans-unit>
<trans-unit id="Recommended relays" xml:space="preserve">
<source>Recommended relays</source>
<target>Recommended relays</target>
<note>Title for view of recommended relays.</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
<source>Reject</source>
@@ -1316,6 +1427,11 @@ Label for filter for seeing your notes and replies (instead of only your notes).
<target>Select a Lightning wallet</target>
<note>Title of section for selecting a Lightning wallet to pay a Lightning invoice.</note>
</trans-unit>
<trans-unit id="Select default emoji" xml:space="preserve">
<source>Select default emoji</source>
<target>Select default emoji</target>
<note>Prompt selection of user's default emoji reaction</note>
</trans-unit>
<trans-unit id="Select default wallet" xml:space="preserve">
<source>Select default wallet</source>
<target>Select default wallet</target>
@@ -1341,6 +1457,11 @@ Label for filter for seeing your notes and replies (instead of only your notes).
<target>Service</target>
<note>Prompt selection of translation service provider.</note>
</trans-unit>
<trans-unit id="Set Status" xml:space="preserve">
<source>Set Status</source>
<target>Set Status</target>
<note>Sidebar menu label to set user status</note>
</trans-unit>
<trans-unit id="Settings" xml:space="preserve">
<source>Settings</source>
<target>Settings</target>
@@ -1370,10 +1491,10 @@ Label for filter for seeing your notes and replies (instead of only your notes).
<note>Button to show a note from a user who has been muted.
Toggle to show or hide user's secret account login key.</note>
</trans-unit>
<trans-unit id="Show +" xml:space="preserve">
<source>Show +</source>
<target>Show +</target>
<note>Button that, when tapped, will show + buttons next to a user's relays.</note>
<trans-unit id="Show general statuses" xml:space="preserve">
<source>Show general statuses</source>
<target>Show general statuses</target>
<note>Settings toggle for enabling general user statuses</note>
</trans-unit>
<trans-unit id="Show less" xml:space="preserve">
<source>Show less</source>
@@ -1386,6 +1507,11 @@ Label for filter for seeing your notes and replies (instead of only your notes).
<note>Button to show entire note.
Button to show more of a long profile description.</note>
</trans-unit>
<trans-unit id="Show music statuses" xml:space="preserve">
<source>Show music statuses</source>
<target>Show music statuses</target>
<note>Settings toggle for enabling now playing music statuses</note>
</trans-unit>
<trans-unit id="Show only from users you follow" xml:space="preserve">
<source>Show only from users you follow</source>
<target>Show only from users you follow</target>
@@ -1416,6 +1542,11 @@ Label for filter for seeing your notes and replies (instead of only your notes).
<target>Sign out</target>
<note>Sidebar menu label to sign out of the account.</note>
</trans-unit>
<trans-unit id="Skip" xml:space="preserve">
<source>Skip</source>
<target>Skip</target>
<note>Button to dismiss the suggested users screen</note>
</trans-unit>
<trans-unit id="Social media has developed into a key way information flows around the world. Unfortunately, our current social media systems are broken" xml:space="preserve">
<source>Social media has developed into a key way information flows around the world. Unfortunately, our current social media systems are broken</source>
<target>Social media has developed into a key way information flows around the world. Unfortunately, our current social media systems are broken</target>
@@ -1467,6 +1598,13 @@ Label for filter for seeing your notes and replies (instead of only your notes).
<target>The go-to iOS Nostr client</target>
<note>Quick description of what Damus is</note>
</trans-unit>
<trans-unit id="The relay you are trying to add is already added.&#10;You're all set!" xml:space="preserve">
<source>The relay you are trying to add is already added.
You're all set!</source>
<target>The relay you are trying to add is already added.
You're all set!</target>
<note>An error message that appears when the user attempts to add a relay that has already been added.</note>
</trans-unit>
<trans-unit id="This is a paid relay, you must pay for notes to be accepted." xml:space="preserve">
<source>This is a paid relay, you must pay for notes to be accepted.</source>
<target>This is a paid relay, you must pay for notes to be accepted.</target>
@@ -1487,11 +1625,6 @@ Label for filter for seeing your notes and replies (instead of only your notes).
<target>This is your secret account key. You need this to access your account. Don't share this with anyone! Save it in a password manager and keep it safe!</target>
<note>Label to describe that a private key is the user's secret account key and what they should do with it.</note>
</trans-unit>
<trans-unit id="This relay is already in your list" xml:space="preserve">
<source>This relay is already in your list</source>
<target>This relay is already in your list</target>
<note>An error message that appears when the user attempts to add a relay that has already been added.</note>
</trans-unit>
<trans-unit id="Thread" xml:space="preserve">
<source>Thread</source>
<target>Thread</target>
@@ -1593,10 +1726,15 @@ Label for filter for seeing your notes and replies (instead of only your notes).
<target>Upload</target>
<note>Button to proceed with uploading.</note>
</trans-unit>
<trans-unit id="User Statuses" xml:space="preserve">
<source>User Statuses</source>
<target>User Statuses</target>
<note>Section header for user profile status settings.</note>
</trans-unit>
<trans-unit id="User has been muted" xml:space="preserve">
<source>User has been muted</source>
<target>User has been muted</target>
<note>Alert message that informs a user was d.</note>
<note>Alert message that informs a user was muted.</note>
</trans-unit>
<trans-unit id="User muted" xml:space="preserve">
<source>User muted</source>
@@ -1688,6 +1826,11 @@ YOU WILL NO LONGER BE ABLE TO LOG INTO DAMUS USING THIS ACCOUNT KEY.
<target>What is Nostr?</target>
<note>Heading text for section describing what is Nostr.</note>
</trans-unit>
<trans-unit id="Who to Follow" xml:space="preserve">
<source>Who to Follow</source>
<target>Who to Follow</target>
<note>Title for a screen displaying suggestions of who to follow</note>
</trans-unit>
<trans-unit id="Why we need Nostr?" xml:space="preserve">
<source>Why we need Nostr?</source>
<target>Why we need Nostr?</target>
@@ -1768,6 +1911,11 @@ YOU WILL NO LONGER BE ABLE TO LOG INTO DAMUS USING THIS ACCOUNT KEY.
Setting to enable Zap Local Notification
Title for section in zap settings that controls general zap preferences.</note>
</trans-unit>
<trans-unit id="https://example.com" xml:space="preserve">
<source>https://example.com</source>
<target>https://example.com</target>
<note>Placeholder as an example of what the user could set so that the link is opened when the status is tapped.</note>
</trans-unit>
<trans-unit id="https://example.com/pic.jpg" xml:space="preserve">
<source>https://example.com/pic.jpg</source>
<target>https://example.com/pic.jpg</target>
@@ -1923,11 +2071,21 @@ YOU WILL NO LONGER BE ABLE TO LOG INTO DAMUS USING THIS ACCOUNT KEY.
<target>%@ and %@ zapped you</target>
<note>Notification that 2 users zapped the current user's profile</note>
</trans-unit>
<trans-unit id="⚡" xml:space="preserve">
<source>⚡</source>
<target>⚡</target>
<note>Placeholder example for an emoji reaction</note>
</trans-unit>
<trans-unit id="📋 Working" xml:space="preserve">
<source>📋 Working</source>
<target>📋 Working</target>
<note>Placeholder as an example of what the user could set as their profile status.</note>
</trans-unit>
</body>
</file>
<file original="damus/en-US.lproj/Localizable.stringsdict" source-language="en-US" target-language="en-US" datatype="plaintext">
<header>
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="14.3.1" build-num="14E300c"/>
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="15.0" build-num="15A240d"/>
</header>
<body>
<trans-unit id="/followed_by_three_and_others:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">

View File

@@ -2,6 +2,8 @@
"CFBundleDisplayName" = "Damus";
/* Bundle name */
"CFBundleName" = "damus";
/* Privacy - Media Library Usage Description */
"NSAppleMusicUsageDescription" = "Damus needs access to your media library for playback statuses";
/* Privacy - Camera Usage Description */
"NSCameraUsageDescription" = "Damus needs access to your camera if you want to upload photos from it";
/* Privacy - Face ID Usage Description */

View File

@@ -3,10 +3,10 @@
"project" : "damus.xcodeproj",
"targetLocale" : "en-US",
"toolInfo" : {
"toolBuildNumber" : "14E300c",
"toolBuildNumber" : "15A240d",
"toolID" : "com.apple.dt.xcode",
"toolName" : "Xcode",
"toolVersion" : "14.3.1"
"toolVersion" : "15.0"
},
"version" : "1.0"
}

View File

@@ -175,6 +175,12 @@ class Ndb {
func lookup_profile_with_txn<Y>(_ pubkey: Pubkey, txn: NdbTxn<Y>) -> ProfileRecord? {
lookup_profile_with_txn_inner(pubkey: pubkey, txn: txn)
}
func process_client_event(_ str: String) -> Bool {
return str.withCString { cstr in
return ndb_process_client_event(ndb.ndb, cstr, Int32(str.utf8.count)) != 0
}
}
func process_event(_ str: String) -> Bool {
return str.withCString { cstr in

View File

@@ -414,7 +414,8 @@ enum ndb_writer_msgtype {
struct ndb_ingester_event {
char *json;
int len;
unsigned client : 1; // ["EVENT", {...}] messages
unsigned len : 31;
};
struct ndb_writer_note {
@@ -730,6 +731,41 @@ static int ndb_process_profile_note(struct ndb_note *note,
return 1;
}
static int ndb_ingester_process_note(secp256k1_context *ctx,
struct ndb_note *note,
size_t note_size,
struct ndb_writer_msg *out)
{
// Verify! If it's an invalid note we don't need to
// bothter writing it to the database
if (!ndb_note_verify(ctx, note->pubkey, note->id, note->sig)) {
ndb_debug("signature verification failed\n");
return 0;
}
// we didn't find anything. let's send it
// to the writer thread
note = realloc(note, note_size);
assert(((uint64_t)note % 4) == 0);
if (note->kind == 0) {
struct ndb_profile_record_builder *b =
&out->profile.record;
ndb_process_profile_note(note, b);
out->type = NDB_WRITER_PROFILE;
out->profile.note.note = note;
out->profile.note.note_len = note_size;
} else {
out->type = NDB_WRITER_NOTE;
out->note.note = note;
out->note.note_len = note_size;
}
return 1;
}
static int ndb_ingester_process_event(secp256k1_context *ctx,
struct ndb_ingester *ingester,
@@ -739,12 +775,16 @@ static int ndb_ingester_process_event(secp256k1_context *ctx,
)
{
struct ndb_tce tce;
struct ndb_fce fce;
struct ndb_note *note;
struct ndb_ingest_controller controller;
struct ndb_id_cb cb;
void *buf;
int ok;
size_t bufsize, note_size;
ok = 0;
// we will use this to check if we already have it in the DB during
// ID parsing
controller.read_txn = read_txn;
@@ -762,6 +802,8 @@ static int ndb_ingester_process_event(secp256k1_context *ctx,
}
note_size =
ev->client ?
ndb_client_event_from_json(ev->json, ev->len, &fce, buf, bufsize, &cb) :
ndb_ws_event_from_json(ev->json, ev->len, &tce, buf, bufsize, &cb);
if (note_size == -42) {
@@ -775,54 +817,51 @@ static int ndb_ingester_process_event(secp256k1_context *ctx,
//ndb_debug("parsed evtype:%d '%.*s'\n", tce.evtype, ev->len, ev->json);
switch (tce.evtype) {
case NDB_TCE_NOTICE: goto cleanup;
case NDB_TCE_EOSE: goto cleanup;
case NDB_TCE_OK: goto cleanup;
case NDB_TCE_EVENT:
note = tce.event.note;
if (note != buf) {
ndb_debug("note buffer not equal to malloc'd buffer\n");
goto cleanup;
if (ev->client) {
switch (fce.evtype) {
case NDB_FCE_EVENT:
note = fce.event.note;
if (note != buf) {
ndb_debug("note buffer not equal to malloc'd buffer\n");
goto cleanup;
}
if (!ndb_ingester_process_note(ctx, note, note_size, out))
goto cleanup;
else {
// we're done with the original json, free it
free(ev->json);
return 1;
}
}
} else {
switch (tce.evtype) {
case NDB_TCE_NOTICE: goto cleanup;
case NDB_TCE_EOSE: goto cleanup;
case NDB_TCE_OK: goto cleanup;
case NDB_TCE_EVENT:
note = tce.event.note;
if (note != buf) {
ndb_debug("note buffer not equal to malloc'd buffer\n");
goto cleanup;
}
// Verify! If it's an invalid note we don't need to
// bothter writing it to the database
if (!ndb_note_verify(ctx, note->pubkey, note->id, note->sig)) {
ndb_debug("signature verification failed\n");
goto cleanup;
if (!ndb_ingester_process_note(ctx, note, note_size, out))
goto cleanup;
else {
// we're done with the original json, free it
free(ev->json);
return 1;
}
}
// we didn't find anything. let's send it
// to the writer thread
note = realloc(note, note_size);
assert(((uint64_t)note % 4) == 0);
if (note->kind == 0) {
struct ndb_profile_record_builder *b =
&out->profile.record;
ndb_process_profile_note(note, b);
out->type = NDB_WRITER_PROFILE;
out->profile.note.note = note;
out->profile.note.note_len = note_size;
} else {
out->type = NDB_WRITER_NOTE;
out->note.note = note;
out->note.note_len = note_size;
}
// there's nothing left to do with the original json, so free it
free(ev->json);
return 1;
}
cleanup:
free(ev->json);
free(buf);
return 0;
return ok;
}
static uint64_t ndb_get_last_key(MDB_txn *txn, MDB_dbi db)
@@ -1089,7 +1128,7 @@ static void ndb_write_version(struct ndb_lmdb *lmdb, MDB_txn *txn, uint64_t vers
return;
}
fprintf(stderr, "writing version %" PRIu64 "\n", version);
//fprintf(stderr, "writing version %" PRIu64 "\n", version);
}
static void *ndb_writer_thread(void *data)
@@ -1317,13 +1356,14 @@ static int ndb_ingester_destroy(struct ndb_ingester *ingester)
}
static int ndb_ingester_queue_event(struct ndb_ingester *ingester,
char *json, int len)
char *json, unsigned len, unsigned client)
{
struct ndb_ingester_msg msg;
msg.type = NDB_INGEST_EVENT;
msg.event.json = json;
msg.event.len = len;
msg.event.client = client;
return threadpool_dispatch(&ingester->tp, &msg);
}
@@ -1431,7 +1471,7 @@ static int ndb_run_migrations(struct ndb *ndb)
latest_version = sizeof(MIGRATIONS) / sizeof(MIGRATIONS[0]);
if ((version = ndb_db_version(ndb)) == -1) {
fprintf(stderr, "run_migrations: no version found, assuming new db\n");
ndb_debug("run_migrations: no version found, assuming new db\n");
version = latest_version;
// no version found. fresh db?
@@ -1442,11 +1482,11 @@ static int ndb_run_migrations(struct ndb *ndb)
return 1;
} else {
fprintf(stderr, "ndb: version %" PRIu64 " found\n", version);
ndb_debug("ndb: version %" PRIu64 " found\n", version);
}
if (version < latest_version)
fprintf(stderr, "nostrdb: migrating v%d -> v%d\n",
ndb_debug("nostrdb: migrating v%d -> v%d\n",
(int)version, (int)latest_version);
for (i = version; i < latest_version; i++) {
@@ -1516,7 +1556,29 @@ void ndb_destroy(struct ndb *ndb)
free(ndb);
}
// Process a nostr event, ie: ["EVENT", "subid", {"content":"..."}...]
// Process a nostr event from a client
//
// ie: ["EVENT", {"content":"..."} ...]
//
// The client-sent variation of ndb_process_event
int ndb_process_client_event(struct ndb *ndb, const char *json, int len)
{
// Since we need to return as soon as possible, and we're not
// making any assumptions about the lifetime of the string, we
// definitely need to copy the json here. In the future once we
// have our thread that manages a websocket connection, we can
// avoid the copy and just use the buffer we get from that
// thread.
char *json_copy = strdupn(json, len);
if (json_copy == NULL)
return 0;
return ndb_ingester_queue_event(&ndb->ingester, json_copy, len, 1);
}
// Process anostr event from a relay,
//
// ie: ["EVENT", "subid", {"content":"..."}...]
//
// This function returns as soon as possible, first copying the passed
// json and then queueing it up for processing. Worker threads then take
@@ -1543,23 +1605,26 @@ int ndb_process_event(struct ndb *ndb, const char *json, int json_len)
if (json_copy == NULL)
return 0;
return ndb_ingester_queue_event(&ndb->ingester, json_copy, json_len);
return ndb_ingester_queue_event(&ndb->ingester, json_copy, json_len, 0);
}
int ndb_process_events(struct ndb *ndb, const char *ldjson, size_t json_len)
int _ndb_process_events(struct ndb *ndb, const char *ldjson, size_t json_len, int client)
{
const char *start, *end, *very_end;
start = ldjson;
end = start + json_len;
very_end = ldjson + json_len;
int (* process)(struct ndb *, const char *, int);
#if DEBUG
int processed = 0;
#endif
process = client ? ndb_process_client_event : ndb_process_event;
while ((end = fast_strchr(start, '\n', very_end - start))) {
//printf("processing '%.*s'\n", (int)(end-start), start);
if (!ndb_process_event(ndb, start, end - start)) {
ndb_debug("ndb_process_event failed\n");
if (!process(ndb, start, end - start)) {
ndb_debug("ndb_process_client_event failed\n");
return 0;
}
start = end + 1;
@@ -1573,6 +1638,16 @@ int ndb_process_events(struct ndb *ndb, const char *ldjson, size_t json_len)
return 1;
}
int ndb_process_client_events(struct ndb *ndb, const char *ldjson, size_t json_len)
{
return _ndb_process_events(ndb, ldjson, json_len, 1);
}
int ndb_process_events(struct ndb *ndb, const char *ldjson, size_t json_len)
{
return _ndb_process_events(ndb, ldjson, json_len, 0);
}
static inline int cursor_push_tag(struct cursor *cur, struct ndb_tag *tag)
{
return cursor_push_u16(cur, tag->count);
@@ -1678,6 +1753,13 @@ static inline int ndb_json_parser_parse(struct ndb_json_parser *p,
return 1;
}
static inline int toksize(jsmntok_t *tok)
{
return tok->end - tok->start;
}
static int cursor_push_unescaped_char(struct cursor *cur, char c1, char c2)
{
switch (c2) {
@@ -2074,11 +2156,6 @@ static inline int jsoneq(const char *json, jsmntok_t *tok, int tok_len,
return 0;
}
static inline int toksize(jsmntok_t *tok)
{
return tok->end - tok->start;
}
static int ndb_builder_finalize_tag(struct ndb_builder *builder,
union ndb_packed_str offset)
{
@@ -2227,6 +2304,37 @@ static int parse_unsigned_int(const char *start, int len, unsigned int *num)
return 1;
}
int ndb_client_event_from_json(const char *json, int len, struct ndb_fce *fce,
unsigned char *buf, int bufsize, struct ndb_id_cb *cb)
{
jsmntok_t *tok = NULL;
int tok_len, res;
struct ndb_json_parser parser;
ndb_json_parser_init(&parser, json, len, buf, bufsize);
if ((res = ndb_json_parser_parse(&parser, cb)) < 0)
return res;
if (parser.num_tokens <= 3 || parser.toks[0].type != JSMN_ARRAY)
return 0;
parser.i = 1;
tok = &parser.toks[parser.i++];
tok_len = toksize(tok);
if (tok->type != JSMN_STRING)
return 0;
if (tok_len == 5 && !memcmp("EVENT", json + tok->start, 5)) {
fce->evtype = NDB_FCE_EVENT;
struct ndb_event *ev = &fce->event;
return ndb_parse_json_note(&parser, &ev->note);
}
return 0;
}
int ndb_ws_event_from_json(const char *json, int len, struct ndb_tce *tce,
unsigned char *buf, int bufsize,
struct ndb_id_cb *cb)
@@ -2239,22 +2347,12 @@ int ndb_ws_event_from_json(const char *json, int len, struct ndb_tce *tce,
tce->subid = "";
ndb_json_parser_init(&parser, json, len, buf, bufsize);
if ((res = ndb_json_parser_parse(&parser, cb)) < 0)
return res;
if (parser.num_tokens < 3 || parser.toks[0].type != JSMN_ARRAY) {
/*
tok = &parser.toks[parser.json_parser.toknext-1];
ndb_debug("failing at not enough takens (%d) or != JSMN_ARRAY @ '%.*s', '%.*s'\n",
parser.num_tokens, 10, json + parser.json_parser.pos,
toksize(tok), json + tok->start);
tok = &parser.toks[parser.json_parser.toknext-2];
ndb_debug("failing at not enough takens (%d) or != JSMN_ARRAY @ '%.*s', '%.*s'\n",
parser.num_tokens, 10, json + parser.json_parser.pos,
toksize(tok), json + tok->start);
*/
if (parser.num_tokens < 3 || parser.toks[0].type != JSMN_ARRAY)
return 0;
}
parser.i = 1;
tok = &parser.toks[parser.i++];

View File

@@ -44,6 +44,11 @@ struct ndb_txn {
void *mdb_txn;
};
// From-client event types
enum fce_type {
NDB_FCE_EVENT = 0x1
};
// To-client event types
enum tce_type {
NDB_TCE_EVENT = 0x1,
@@ -80,6 +85,14 @@ struct ndb_command_result {
};
// From-client event
struct ndb_fce {
enum fce_type evtype;
union {
struct ndb_event event;
};
};
// To-client event
struct ndb_tce {
enum tce_type evtype;
@@ -177,6 +190,8 @@ int ndb_init(struct ndb **ndb, const char *dbdir, size_t mapsize, int ingester_t
int ndb_db_version(struct ndb *ndb);
int ndb_process_event(struct ndb *, const char *json, int len);
int ndb_process_events(struct ndb *, const char *ldjson, size_t len);
int ndb_process_client_event(struct ndb *, const char *json, int len);
int ndb_process_client_events(struct ndb *, const char *json, size_t len);
int ndb_begin_query(struct ndb *, struct ndb_txn *);
int ndb_search_profile(struct ndb_txn *txn, struct ndb_search *search, const char *query);
int ndb_search_profile_next(struct ndb_search *search);
@@ -192,6 +207,7 @@ void ndb_destroy(struct ndb *);
// BUILDER
int ndb_parse_json_note(struct ndb_json_parser *, struct ndb_note **);
int ndb_client_event_from_json(const char *json, int len, struct ndb_fce *fce, unsigned char *buf, int bufsize, struct ndb_id_cb *cb);
int ndb_ws_event_from_json(const char *json, int len, struct ndb_tce *tce, unsigned char *buf, int bufsize, struct ndb_id_cb *);
int ndb_note_from_json(const char *json, int len, struct ndb_note **, unsigned char *buf, int buflen);
int ndb_builder_init(struct ndb_builder *builder, unsigned char *buf, int bufsize);