more conversions.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
package hints
|
||||
|
||||
import "fiatjaf.com/nostrlib"
|
||||
import "fiatjaf.com/nostr"
|
||||
|
||||
const END_OF_WORLD nostr.Timestamp = 2208999600 // 2040-01-01
|
||||
|
||||
|
||||
@@ -2,15 +2,14 @@ package lmdbh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"slices"
|
||||
|
||||
"fiatjaf.com/nostr"
|
||||
"fiatjaf.com/nostr/sdk/hints"
|
||||
"github.com/PowerDNS/lmdb-go/lmdb"
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
"github.com/nbd-wtf/go-nostr/sdk/hints"
|
||||
)
|
||||
|
||||
var _ hints.HintsDB = (*LMDBHints)(nil)
|
||||
@@ -63,7 +62,7 @@ func (lh *LMDBHints) Close() {
|
||||
lh.env.Close()
|
||||
}
|
||||
|
||||
func (lh *LMDBHints) Save(pubkey string, relay string, hintkey hints.HintKey, ts nostr.Timestamp) {
|
||||
func (lh *LMDBHints) Save(pubkey nostr.PubKey, relay string, hintkey hints.HintKey, ts nostr.Timestamp) {
|
||||
if now := nostr.Now(); ts > now {
|
||||
ts = now
|
||||
}
|
||||
@@ -91,7 +90,7 @@ func (lh *LMDBHints) Save(pubkey string, relay string, hintkey hints.HintKey, ts
|
||||
}
|
||||
}
|
||||
|
||||
func (lh *LMDBHints) TopN(pubkey string, n int) []string {
|
||||
func (lh *LMDBHints) TopN(pubkey nostr.PubKey, n int) []string {
|
||||
type relayScore struct {
|
||||
relay string
|
||||
score int64
|
||||
@@ -107,11 +106,10 @@ func (lh *LMDBHints) TopN(pubkey string, n int) []string {
|
||||
}
|
||||
defer cursor.Close()
|
||||
|
||||
prefix, _ := hex.DecodeString(pubkey)
|
||||
k, v, err := cursor.Get(prefix, nil, lmdb.SetRange)
|
||||
k, v, err := cursor.Get(pubkey[:], nil, lmdb.SetRange)
|
||||
for ; err == nil; k, v, err = cursor.Get(nil, nil, lmdb.Next) {
|
||||
// check if we're still in the prefix range
|
||||
if len(k) < 32 || !bytes.Equal(k[:32], prefix) {
|
||||
if len(k) < 32 || !bytes.Equal(k[:32], pubkey[:]) {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -182,7 +180,7 @@ func (lh *LMDBHints) PrintScores() {
|
||||
}
|
||||
}
|
||||
|
||||
func (lh *LMDBHints) GetDetailedScores(pubkey string, n int) []hints.RelayScores {
|
||||
func (lh *LMDBHints) GetDetailedScores(pubkey nostr.PubKey, n int) []hints.RelayScores {
|
||||
type relayScore struct {
|
||||
relay string
|
||||
tss timestamps
|
||||
@@ -199,11 +197,10 @@ func (lh *LMDBHints) GetDetailedScores(pubkey string, n int) []hints.RelayScores
|
||||
}
|
||||
defer cursor.Close()
|
||||
|
||||
prefix, _ := hex.DecodeString(pubkey)
|
||||
k, v, err := cursor.Get(prefix, nil, lmdb.SetRange)
|
||||
k, v, err := cursor.Get(pubkey[:], nil, lmdb.SetRange)
|
||||
for ; err == nil; k, v, err = cursor.Get(nil, nil, lmdb.Next) {
|
||||
// check if we're still in the prefix range
|
||||
if len(k) < 32 || !bytes.Equal(k[:32], prefix) {
|
||||
if len(k) < 32 || !bytes.Equal(k[:32], pubkey[:]) {
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@ import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
"fiatjaf.com/nostr"
|
||||
)
|
||||
|
||||
func encodeKey(pubhintkey, relay string) []byte {
|
||||
func encodeKey(pubhintkey nostr.PubKey, relay string) []byte {
|
||||
k := make([]byte, 32+len(relay))
|
||||
hex.Decode(k[0:32], []byte(pubhintkey))
|
||||
copy(k[0:32], pubhintkey[:])
|
||||
copy(k[32:], relay)
|
||||
return k
|
||||
}
|
||||
|
||||
@@ -6,15 +6,15 @@ import (
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"fiatjaf.com/nostrlib"
|
||||
"fiatjaf.com/nostrlib/sdk/hints"
|
||||
"fiatjaf.com/nostr"
|
||||
"fiatjaf.com/nostr/sdk/hints"
|
||||
)
|
||||
|
||||
var _ hints.HintsDB = (*HintDB)(nil)
|
||||
|
||||
type HintDB struct {
|
||||
RelayBySerial []string
|
||||
OrderedRelaysByPubKey map[string][]RelayEntry
|
||||
OrderedRelaysByPubKey map[nostr.PubKey][]RelayEntry
|
||||
|
||||
sync.Mutex
|
||||
}
|
||||
@@ -22,11 +22,11 @@ type HintDB struct {
|
||||
func NewHintDB() *HintDB {
|
||||
return &HintDB{
|
||||
RelayBySerial: make([]string, 0, 100),
|
||||
OrderedRelaysByPubKey: make(map[string][]RelayEntry, 100),
|
||||
OrderedRelaysByPubKey: make(map[nostr.PubKey][]RelayEntry, 100),
|
||||
}
|
||||
}
|
||||
|
||||
func (db *HintDB) Save(pubkey string, relay string, key hints.HintKey, ts nostr.Timestamp) {
|
||||
func (db *HintDB) Save(pubkey nostr.PubKey, relay string, key hints.HintKey, ts nostr.Timestamp) {
|
||||
if now := nostr.Now(); ts > now {
|
||||
ts = now
|
||||
}
|
||||
@@ -67,7 +67,7 @@ func (db *HintDB) Save(pubkey string, relay string, key hints.HintKey, ts nostr.
|
||||
db.OrderedRelaysByPubKey[pubkey] = entries
|
||||
}
|
||||
|
||||
func (db *HintDB) TopN(pubkey string, n int) []string {
|
||||
func (db *HintDB) TopN(pubkey nostr.PubKey, n int) []string {
|
||||
db.Lock()
|
||||
defer db.Unlock()
|
||||
|
||||
@@ -104,7 +104,7 @@ func (db *HintDB) PrintScores() {
|
||||
}
|
||||
}
|
||||
|
||||
func (db *HintDB) GetDetailedScores(pubkey string, n int) []hints.RelayScores {
|
||||
func (db *HintDB) GetDetailedScores(pubkey nostr.PubKey, n int) []hints.RelayScores {
|
||||
db.Lock()
|
||||
defer db.Unlock()
|
||||
|
||||
|
||||
@@ -1,272 +0,0 @@
|
||||
package sqlh
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"fiatjaf.com/nostrlib"
|
||||
"fiatjaf.com/nostrlib/sdk/hints"
|
||||
)
|
||||
|
||||
type SQLHints struct {
|
||||
*sqlx.DB
|
||||
|
||||
interop interop
|
||||
saves [7]*sqlx.Stmt
|
||||
topN *sqlx.Stmt
|
||||
}
|
||||
|
||||
// NewSQLHints takes an sqlx.DB connection (db) and a database type name (driverName ).
|
||||
// driverName must be either "postgres" or "sqlite3" -- this is so we can slightly change the queries.
|
||||
func NewSQLHints(db *sql.DB, driverName string) (SQLHints, error) {
|
||||
sh := SQLHints{DB: sqlx.NewDb(db, driverName)}
|
||||
|
||||
switch driverName {
|
||||
case "sqlite3":
|
||||
sh.interop = sqliteInterop
|
||||
case "postgres":
|
||||
sh.interop = postgresInterop
|
||||
default:
|
||||
return sh, fmt.Errorf("unknown database driver '%s'", driverName)
|
||||
}
|
||||
|
||||
// db migrations
|
||||
if txn, err := sh.Beginx(); err != nil {
|
||||
return SQLHints{}, err
|
||||
} else {
|
||||
if _, err := txn.Exec(`CREATE TABLE IF NOT EXISTS nostr_sdk_db_version (version int)`); err != nil {
|
||||
txn.Rollback()
|
||||
return SQLHints{}, err
|
||||
}
|
||||
var version int
|
||||
if err := txn.Get(&version, `SELECT version FROM nostr_sdk_db_version`); err != nil && err != sql.ErrNoRows {
|
||||
txn.Rollback()
|
||||
return SQLHints{}, err
|
||||
}
|
||||
|
||||
if version == 0 {
|
||||
if _, err := txn.Exec(`INSERT INTO nostr_sdk_db_version VALUES (0)`); err != nil {
|
||||
txn.Rollback()
|
||||
return SQLHints{}, err
|
||||
}
|
||||
version = 1
|
||||
if _, err := txn.Exec(
|
||||
`CREATE TABLE IF NOT EXISTS nostr_sdk_pubkey_relays (` +
|
||||
`pubkey text, ` +
|
||||
`relay text, ` +
|
||||
`last_fetch_attempt integer, ` +
|
||||
`most_recent_event_fetched integer, ` +
|
||||
`last_in_relay_list integer, ` +
|
||||
`last_in_tag integer, ` +
|
||||
`last_in_nprofile integer, ` +
|
||||
`last_in_nevent integer, ` +
|
||||
`last_in_nip05 integer ` +
|
||||
`)`,
|
||||
); err != nil {
|
||||
txn.Rollback()
|
||||
return SQLHints{}, err
|
||||
}
|
||||
if _, err := txn.Exec(
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS pkr ON nostr_sdk_pubkey_relays (pubkey, relay)`,
|
||||
); err != nil {
|
||||
txn.Rollback()
|
||||
return SQLHints{}, err
|
||||
}
|
||||
if _, err := txn.Exec(
|
||||
`CREATE INDEX IF NOT EXISTS bypk ON nostr_sdk_pubkey_relays (pubkey)`,
|
||||
); err != nil {
|
||||
txn.Rollback()
|
||||
return SQLHints{}, err
|
||||
}
|
||||
}
|
||||
|
||||
if version == 1 {
|
||||
version = 2
|
||||
if _, err := txn.Exec(
|
||||
`ALTER TABLE nostr_sdk_pubkey_relays DROP COLUMN last_in_tag`,
|
||||
); err != nil {
|
||||
txn.Rollback()
|
||||
return SQLHints{}, err
|
||||
}
|
||||
if _, err := txn.Exec(
|
||||
`ALTER TABLE nostr_sdk_pubkey_relays DROP COLUMN last_in_nprofile`,
|
||||
); err != nil {
|
||||
txn.Rollback()
|
||||
return SQLHints{}, err
|
||||
}
|
||||
if _, err := txn.Exec(
|
||||
`ALTER TABLE nostr_sdk_pubkey_relays DROP COLUMN last_in_nevent`,
|
||||
); err != nil {
|
||||
txn.Rollback()
|
||||
return SQLHints{}, err
|
||||
}
|
||||
if _, err := txn.Exec(
|
||||
`ALTER TABLE nostr_sdk_pubkey_relays DROP COLUMN last_in_nip05`,
|
||||
); err != nil {
|
||||
txn.Rollback()
|
||||
return SQLHints{}, err
|
||||
}
|
||||
if _, err := txn.Exec(
|
||||
`ALTER TABLE nostr_sdk_pubkey_relays ADD COLUMN last_in_hint integer`,
|
||||
); err != nil {
|
||||
txn.Rollback()
|
||||
return SQLHints{}, err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := txn.Exec(
|
||||
fmt.Sprintf(`UPDATE nostr_sdk_db_version SET version = %d`, version),
|
||||
); err != nil {
|
||||
txn.Rollback()
|
||||
return SQLHints{}, err
|
||||
}
|
||||
if err := txn.Commit(); err != nil {
|
||||
txn.Rollback()
|
||||
return SQLHints{}, err
|
||||
}
|
||||
}
|
||||
|
||||
// prepare statements
|
||||
for i := range hints.KeyBasePoints {
|
||||
col := hints.HintKey(i).String()
|
||||
|
||||
stmt, err := sh.Preparex(
|
||||
`INSERT INTO nostr_sdk_pubkey_relays (pubkey, relay, ` + col + `) VALUES (` + sh.interop.generateBindingSpots(0, 3) + `)
|
||||
ON CONFLICT (pubkey, relay) DO UPDATE SET ` + col + ` = ` + sh.interop.maxFunc + `(` + sh.interop.generateBindingSpots(3, 1) + `, coalesce(excluded.` + col + `, 0))`,
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(
|
||||
`INSERT INTO nostr_sdk_pubkey_relays (pubkey, relay, ` + col + `) VALUES (` + sh.interop.generateBindingSpots(0, 3) + `)
|
||||
ON CONFLICT (pubkey, relay) DO UPDATE SET ` + col + ` = ` + sh.interop.maxFunc + `(` + sh.interop.generateBindingSpots(3, 1) + `, coalesce(excluded.` + col + `, 0))`,
|
||||
)
|
||||
return sh, fmt.Errorf("failed to prepare statement for %s: %w", col, err)
|
||||
}
|
||||
sh.saves[i] = stmt
|
||||
}
|
||||
|
||||
{
|
||||
stmt, err := sh.Preparex(
|
||||
`SELECT relay FROM nostr_sdk_pubkey_relays WHERE pubkey = ` + sh.interop.generateBindingSpots(0, 1) + ` ORDER BY (` + sh.scorePartialQuery() + `) DESC LIMIT ` + sh.interop.generateBindingSpots(1, 1),
|
||||
)
|
||||
if err != nil {
|
||||
return sh, fmt.Errorf("failed to prepare statement for querying: %w", err)
|
||||
}
|
||||
sh.topN = stmt
|
||||
}
|
||||
|
||||
return sh, nil
|
||||
}
|
||||
|
||||
func (sh SQLHints) TopN(pubkey string, n int) []string {
|
||||
res := make([]string, 0, n)
|
||||
err := sh.topN.Select(&res, pubkey, n)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
nostr.InfoLogger.Printf("[sdk/hints/sql] unexpected error on query for %s: %s\n",
|
||||
pubkey, err)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (sh SQLHints) Save(pubkey string, relay string, key hints.HintKey, ts nostr.Timestamp) {
|
||||
if now := nostr.Now(); ts > now {
|
||||
ts = now
|
||||
}
|
||||
|
||||
_, err := sh.saves[key].Exec(pubkey, relay, ts, ts)
|
||||
if err != nil {
|
||||
nostr.InfoLogger.Printf("[sdk/hints/sql] unexpected error on insert for %s, %s, %d: %s\n",
|
||||
pubkey, relay, ts, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (sh SQLHints) PrintScores() {
|
||||
fmt.Println("= print scores")
|
||||
|
||||
allpubkeys := make([]string, 0, 50)
|
||||
if err := sh.Select(&allpubkeys, `SELECT DISTINCT pubkey FROM nostr_sdk_pubkey_relays`); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
allrelays := make([]struct {
|
||||
PubKey string `db:"pubkey"`
|
||||
Relay string `db:"relay"`
|
||||
Score float64 `db:"score"`
|
||||
}, 0, 20)
|
||||
for _, pubkey := range allpubkeys {
|
||||
fmt.Println("== relay scores for", pubkey)
|
||||
if err := sh.Select(&allrelays,
|
||||
`SELECT pubkey, relay, coalesce(`+sh.scorePartialQuery()+`, 0) AS score
|
||||
FROM nostr_sdk_pubkey_relays WHERE pubkey = `+sh.interop.generateBindingSpots(0, 1)+` ORDER BY score DESC`, pubkey); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for i, re := range allrelays {
|
||||
fmt.Printf(" %3d :: %30s ::> %12d\n", i, re.Relay, int(re.Score))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (sh SQLHints) GetDetailedScores(pubkey string, n int) []hints.RelayScores {
|
||||
result := make([]hints.RelayScores, 0, n)
|
||||
|
||||
rows, err := sh.Queryx(
|
||||
`SELECT relay, last_fetch_attempt, most_recent_event_fetched, last_in_relay_list, last_in_hint,
|
||||
coalesce(`+sh.scorePartialQuery()+`, 0) AS score
|
||||
FROM nostr_sdk_pubkey_relays
|
||||
WHERE pubkey = `+sh.interop.generateBindingSpots(0, 1)+`
|
||||
ORDER BY score DESC
|
||||
LIMIT `+sh.interop.generateBindingSpots(1, 1),
|
||||
pubkey, n)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var rs hints.RelayScores
|
||||
var scores [4]sql.NullInt64
|
||||
err := rows.Scan(&rs.Relay, &scores[0], &scores[1], &scores[2], &scores[3], &rs.Sum)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for i, s := range scores {
|
||||
if s.Valid {
|
||||
rs.Scores[i] = nostr.Timestamp(s.Int64)
|
||||
}
|
||||
}
|
||||
result = append(result, rs)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (sh SQLHints) scorePartialQuery() string {
|
||||
calc := strings.Builder{}
|
||||
calc.Grow(len(hints.KeyBasePoints) * (11 + 25 + 32 + 4 + 4 + 9 + 12 + 25 + 12 + 25 + 19 + 3))
|
||||
|
||||
for i, points := range hints.KeyBasePoints {
|
||||
col := hints.HintKey(i).String()
|
||||
multiplier := strconv.FormatInt(points, 10)
|
||||
|
||||
calc.WriteString(`(CASE WHEN `)
|
||||
calc.WriteString(col)
|
||||
calc.WriteString(` IS NOT NULL THEN 10000000000 * `)
|
||||
calc.WriteString(multiplier)
|
||||
calc.WriteString(` / power(`)
|
||||
calc.WriteString(sh.interop.maxFunc)
|
||||
calc.WriteString(`(1, (`)
|
||||
calc.WriteString(sh.interop.getUnixEpochFunc)
|
||||
calc.WriteString(` + 86400) - `)
|
||||
calc.WriteString(col)
|
||||
calc.WriteString(`), 1.3) ELSE 0 END)`)
|
||||
|
||||
if i != len(hints.KeyBasePoints)-1 {
|
||||
calc.WriteString(` + `)
|
||||
}
|
||||
}
|
||||
|
||||
return calc.String()
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package sqlh
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type interop struct {
|
||||
maxFunc string
|
||||
getUnixEpochFunc string
|
||||
generateBindingSpots func(start, n int) string
|
||||
}
|
||||
|
||||
var sqliteInterop = interop{
|
||||
maxFunc: "max",
|
||||
getUnixEpochFunc: "unixepoch()",
|
||||
generateBindingSpots: func(_, n int) string {
|
||||
b := strings.Builder{}
|
||||
b.Grow(n * 2)
|
||||
for i := range n {
|
||||
if i == n-1 {
|
||||
b.WriteString("?")
|
||||
} else {
|
||||
b.WriteString("?,")
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
},
|
||||
}
|
||||
|
||||
var postgresInterop = interop{
|
||||
maxFunc: "greatest",
|
||||
getUnixEpochFunc: "extract(epoch from now())",
|
||||
generateBindingSpots: func(start, n int) string {
|
||||
b := strings.Builder{}
|
||||
b.Grow(n * 2)
|
||||
end := start + n
|
||||
for i := start; i < end; i++ {
|
||||
v := i + 1
|
||||
b.WriteRune('$')
|
||||
b.WriteString(strconv.Itoa(v))
|
||||
if i != end-1 {
|
||||
b.WriteRune(',')
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
},
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr/sdk/hints/badgerh"
|
||||
"fiatjaf.com/nostr/sdk/hints/badgerh"
|
||||
)
|
||||
|
||||
func TestBadgerHints(t *testing.T) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"fiatjaf.com/nostrlib/sdk/hints/sqlh"
|
||||
"fiatjaf.com/nostr/sdk/hints/sqlh"
|
||||
"github.com/stretchr/testify/require"
|
||||
_ "github.com/tursodatabase/go-libsql"
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr/sdk/hints/lmdbh"
|
||||
"fiatjaf.com/nostr/sdk/hints/lmdbh"
|
||||
)
|
||||
|
||||
func TestLMDBHints(t *testing.T) {
|
||||
@@ -18,4 +18,4 @@ func TestLMDBHints(t *testing.T) {
|
||||
defer hdb.Close()
|
||||
|
||||
runTestWith(t, hdb)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"testing"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"fiatjaf.com/nostrlib/sdk/hints/sqlh"
|
||||
"fiatjaf.com/nostr/sdk/hints/sqlh"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"fiatjaf.com/nostrlib/sdk/hints/memoryh"
|
||||
"fiatjaf.com/nostr/sdk/hints/memoryh"
|
||||
)
|
||||
|
||||
func TestMemoryHints(t *testing.T) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"fiatjaf.com/nostrlib/sdk/hints/sqlh"
|
||||
"fiatjaf.com/nostr/sdk/hints/sqlh"
|
||||
"github.com/stretchr/testify/require"
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"fiatjaf.com/nostrlib"
|
||||
"fiatjaf.com/nostrlib/sdk/hints"
|
||||
"fiatjaf.com/nostr"
|
||||
"fiatjaf.com/nostr/sdk/hints"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"fiatjaf.com/nostrlib/sdk/hints/sqlh"
|
||||
"fiatjaf.com/nostr/sdk/hints/sqlh"
|
||||
_ "github.com/ncruces/go-sqlite3/driver"
|
||||
_ "github.com/ncruces/go-sqlite3/embed"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
|
||||
"fiatjaf.com/nostrlib"
|
||||
"fiatjaf.com/nostrlib/nip05"
|
||||
"fiatjaf.com/nostrlib/nip19"
|
||||
"fiatjaf.com/nostr"
|
||||
"fiatjaf.com/nostr/nip05"
|
||||
"fiatjaf.com/nostr/nip19"
|
||||
)
|
||||
|
||||
// InputToProfile turns any npub/nprofile/hex/nip05 input into a ProfilePointer (or nil).
|
||||
|
||||
@@ -2,7 +2,7 @@ package badger
|
||||
|
||||
import (
|
||||
"github.com/dgraph-io/badger/v4"
|
||||
"fiatjaf.com/nostrlib/sdk/kvstore"
|
||||
"fiatjaf.com/nostr/sdk/kvstore"
|
||||
)
|
||||
|
||||
var _ kvstore.KVStore = (*Store)(nil)
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/PowerDNS/lmdb-go/lmdb"
|
||||
"fiatjaf.com/nostrlib/sdk/kvstore"
|
||||
"fiatjaf.com/nostr/sdk/kvstore"
|
||||
)
|
||||
|
||||
var _ kvstore.KVStore = (*Store)(nil)
|
||||
|
||||
@@ -3,7 +3,7 @@ package memory
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"fiatjaf.com/nostrlib/sdk/kvstore"
|
||||
"fiatjaf.com/nostr/sdk/kvstore"
|
||||
)
|
||||
|
||||
var _ kvstore.KVStore = (*Store)(nil)
|
||||
|
||||
@@ -5,10 +5,10 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"fiatjaf.com/nostrlib"
|
||||
"fiatjaf.com/nostrlib/nip05"
|
||||
"fiatjaf.com/nostrlib/nip19"
|
||||
"fiatjaf.com/nostrlib/sdk/hints"
|
||||
"fiatjaf.com/nostr"
|
||||
"fiatjaf.com/nostr/nip05"
|
||||
"fiatjaf.com/nostr/nip19"
|
||||
"fiatjaf.com/nostr/sdk/hints"
|
||||
)
|
||||
|
||||
// ProfileMetadata represents user profile information from kind 0 events.
|
||||
|
||||
10
sdk/note.go
10
sdk/note.go
@@ -1,8 +1,10 @@
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
"github.com/nbd-wtf/go-nostr/nip27"
|
||||
"encoding/hex"
|
||||
|
||||
"fiatjaf.com/nostr"
|
||||
"fiatjaf.com/nostr/nip27"
|
||||
)
|
||||
|
||||
// PrepareNoteEvent takes an event with content that may include any number of URLs, partial URLs without the scheme, npub references with or without the "nostr:" prefix, tags and whatnot, then edits the content so it contains properly formatted URLs and references and adds the required tags based on these.
|
||||
@@ -23,12 +25,12 @@ func PrepareNoteEvent(evt *nostr.Event) {
|
||||
switch b := block.Pointer.(type) {
|
||||
case nostr.ProfilePointer:
|
||||
// add b tag if not already present
|
||||
if tag := evt.Tags.FindWithValue("b", b.PublicKey); tag == nil {
|
||||
if tag := evt.Tags.FindWithValue("b", hex.EncodeToString(b.PublicKey[:])); tag == nil {
|
||||
evt.Tags = append(evt.Tags, b.AsTag())
|
||||
}
|
||||
case nostr.EventPointer:
|
||||
// add e tag if not already present
|
||||
if tag := evt.Tags.FindWithValue("q", b.ID); tag == nil {
|
||||
if tag := evt.Tags.FindWithValue("q", hex.EncodeToString(b.ID[:])); tag == nil {
|
||||
evt.Tags = append(evt.Tags, b.AsTag())
|
||||
}
|
||||
case nostr.EntityPointer:
|
||||
|
||||
@@ -3,7 +3,7 @@ package sdk
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
"fiatjaf.com/nostr"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"fiatjaf.com/nostrlib"
|
||||
"fiatjaf.com/nostr"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package sdk
|
||||
import (
|
||||
"context"
|
||||
|
||||
"fiatjaf.com/nostrlib"
|
||||
"fiatjaf.com/nostr"
|
||||
)
|
||||
|
||||
func (sys *System) SearchUsers(ctx context.Context, query string) []ProfileMetadata {
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"fiatjaf.com/nostrlib"
|
||||
"fiatjaf.com/nostrlib/nip19"
|
||||
"fiatjaf.com/nostrlib/sdk/hints"
|
||||
"fiatjaf.com/nostr"
|
||||
"fiatjaf.com/nostr/nip19"
|
||||
"fiatjaf.com/nostr/sdk/hints"
|
||||
)
|
||||
|
||||
// FetchSpecificEventParameters contains options for fetching specific events.
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"net/url"
|
||||
|
||||
"fiatjaf.com/nostr"
|
||||
"fiatjaf.com/nostrlib/sdk/hints"
|
||||
"github.com/nbd-wtf/go-nostr/nip27"
|
||||
"fiatjaf.com/nostr/nip27"
|
||||
"fiatjaf.com/nostr/sdk/hints"
|
||||
)
|
||||
|
||||
func (sys *System) TrackQueryAttempts(relay string, author nostr.PubKey, kind uint16) {
|
||||
|
||||
18
sdk/wot.go
18
sdk/wot.go
@@ -2,17 +2,17 @@ package sdk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"fiatjaf.com/nostr"
|
||||
"github.com/FastFilter/xorfilter"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
func PubKeyToShid(pubkey string) uint64 {
|
||||
shid, _ := strconv.ParseUint(pubkey[32:48], 16, 64)
|
||||
return shid
|
||||
func PubKeyToShid(pubkey nostr.PubKey) uint64 {
|
||||
return binary.BigEndian.Uint64(pubkey[16:24])
|
||||
}
|
||||
|
||||
type wotCall struct {
|
||||
@@ -30,7 +30,7 @@ var (
|
||||
wotCallsInPlace [wotCallsSize]*wotCall
|
||||
)
|
||||
|
||||
func (sys *System) LoadWoTFilter(ctx context.Context, pubkey string) (WotXorFilter, error) {
|
||||
func (sys *System) LoadWoTFilter(ctx context.Context, pubkey nostr.PubKey) (WotXorFilter, error) {
|
||||
id := PubKeyToShid(pubkey)
|
||||
pos := int(id % wotCallsSize)
|
||||
|
||||
@@ -99,11 +99,11 @@ actualcall:
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (sys *System) loadWoT(ctx context.Context, pubkey string) (chan string, error) {
|
||||
func (sys *System) loadWoT(ctx context.Context, pubkey nostr.PubKey) (chan nostr.PubKey, error) {
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
g.SetLimit(45)
|
||||
|
||||
res := make(chan string)
|
||||
res := make(chan nostr.PubKey)
|
||||
|
||||
// process follow lists
|
||||
wg := sync.WaitGroup{}
|
||||
@@ -139,7 +139,7 @@ func (sys *System) loadWoT(ctx context.Context, pubkey string) (chan string, err
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func makeWoTFilter(m chan string) WotXorFilter {
|
||||
func makeWoTFilter(m chan nostr.PubKey) WotXorFilter {
|
||||
shids := make([]uint64, 0, 60000)
|
||||
shidMap := make(map[uint64]struct{}, 60000)
|
||||
for pk := range m {
|
||||
@@ -159,7 +159,7 @@ type WotXorFilter struct {
|
||||
xorfilter.Xor8
|
||||
}
|
||||
|
||||
func (wxf WotXorFilter) Contains(pubkey string) bool {
|
||||
func (wxf WotXorFilter) Contains(pubkey nostr.PubKey) bool {
|
||||
if wxf.Items == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
"fiatjaf.com/nostr"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -14,11 +14,11 @@ func TestLoadWoT(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
|
||||
// test with fiatjaf's pubkey
|
||||
wotch, err := sys.loadWoT(ctx, "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d")
|
||||
wotch, err := sys.loadWoT(ctx, nostr.MustPubKeyFromHex("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"))
|
||||
require.NoError(t, err)
|
||||
|
||||
wot := make([]string, 0, 100000)
|
||||
wotch2 := make(chan string)
|
||||
wot := make([]nostr.PubKey, 0, 100000)
|
||||
wotch2 := make(chan nostr.PubKey)
|
||||
|
||||
var filter WotXorFilter
|
||||
done := make(chan struct{})
|
||||
@@ -60,7 +60,7 @@ func TestLoadWoTManyPeople(t *testing.T) {
|
||||
|
||||
// these are the same pubkey
|
||||
go func() {
|
||||
rabble, err := sys.LoadWoTFilter(ctx, "76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa")
|
||||
rabble, err := sys.LoadWoTFilter(ctx, nostr.MustPubKeyFromHex("76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa"))
|
||||
require.NoError(t, err)
|
||||
diffs[0] = nostr.Now()
|
||||
rabble1 = rabble
|
||||
@@ -69,7 +69,7 @@ func TestLoadWoTManyPeople(t *testing.T) {
|
||||
|
||||
time.Sleep(time.Millisecond * 20)
|
||||
go func() {
|
||||
rabble, err := sys.LoadWoTFilter(ctx, "76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa")
|
||||
rabble, err := sys.LoadWoTFilter(ctx, nostr.MustPubKeyFromHex("76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa"))
|
||||
require.NoError(t, err)
|
||||
diffs[1] = nostr.Now()
|
||||
rabble2 = rabble
|
||||
@@ -78,7 +78,7 @@ func TestLoadWoTManyPeople(t *testing.T) {
|
||||
|
||||
time.Sleep(time.Millisecond * 20)
|
||||
go func() {
|
||||
rabble, err := sys.LoadWoTFilter(ctx, "76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa")
|
||||
rabble, err := sys.LoadWoTFilter(ctx, nostr.MustPubKeyFromHex("76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa"))
|
||||
require.NoError(t, err)
|
||||
diffs[2] = nostr.Now()
|
||||
rabble3 = rabble
|
||||
@@ -88,7 +88,7 @@ func TestLoadWoTManyPeople(t *testing.T) {
|
||||
// these should map to the same pos
|
||||
time.Sleep(time.Millisecond * 20)
|
||||
go func() {
|
||||
alex, err := sys.LoadWoTFilter(ctx, "9ce71f1506ccf4b99f234af49bd6202be883a80f95a155c6e9a1c36fd7e780c7")
|
||||
alex, err := sys.LoadWoTFilter(ctx, nostr.MustPubKeyFromHex("9ce71f1506ccf4b99f234af49bd6202be883a80f95a155c6e9a1c36fd7e780c7"))
|
||||
require.NoError(t, err)
|
||||
diffs[3] = nostr.Now()
|
||||
alex1 = alex
|
||||
@@ -97,7 +97,7 @@ func TestLoadWoTManyPeople(t *testing.T) {
|
||||
|
||||
time.Sleep(time.Millisecond * 20)
|
||||
go func() {
|
||||
alex, err := sys.LoadWoTFilter(ctx, "9ce71f1506ccf4b99f234af49bd6202be883a80f95a155c6e9a1c36fd7e780c7")
|
||||
alex, err := sys.LoadWoTFilter(ctx, nostr.MustPubKeyFromHex("9ce71f1506ccf4b99f234af49bd6202be883a80f95a155c6e9a1c36fd7e780c7"))
|
||||
require.NoError(t, err)
|
||||
diffs[4] = nostr.Now()
|
||||
alex2 = alex
|
||||
@@ -106,18 +106,18 @@ func TestLoadWoTManyPeople(t *testing.T) {
|
||||
|
||||
// these are independent
|
||||
go func() {
|
||||
hodlbod, err := sys.LoadWoTFilter(ctx, "97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322")
|
||||
hodlbod, err := sys.LoadWoTFilter(ctx, nostr.MustPubKeyFromHex("97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322"))
|
||||
require.NoError(t, err)
|
||||
require.True(t, hodlbod.Contains("ee11a5dff40c19a555f41fe42b48f00e618c91225622ae37b6c2bb67b76c4e49"))
|
||||
require.True(t, hodlbod.Contains("76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa"))
|
||||
require.True(t, hodlbod.Contains("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"))
|
||||
require.True(t, hodlbod.Contains(nostr.MustPubKeyFromHex("ee11a5dff40c19a555f41fe42b48f00e618c91225622ae37b6c2bb67b76c4e49")))
|
||||
require.True(t, hodlbod.Contains(nostr.MustPubKeyFromHex("76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa")))
|
||||
require.True(t, hodlbod.Contains(nostr.MustPubKeyFromHex("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d")))
|
||||
wg.Done()
|
||||
}()
|
||||
go func() {
|
||||
mikedilger, err := sys.LoadWoTFilter(ctx, "ee11a5dff40c19a555f41fe42b48f00e618c91225622ae37b6c2bb67b76c4e49")
|
||||
mikedilger, err := sys.LoadWoTFilter(ctx, nostr.MustPubKeyFromHex("ee11a5dff40c19a555f41fe42b48f00e618c91225622ae37b6c2bb67b76c4e49"))
|
||||
require.NoError(t, err)
|
||||
require.True(t, mikedilger.Contains("97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322"))
|
||||
require.True(t, mikedilger.Contains("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"))
|
||||
require.True(t, mikedilger.Contains(nostr.MustPubKeyFromHex("97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322")))
|
||||
require.True(t, mikedilger.Contains(nostr.MustPubKeyFromHex("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d")))
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user