Fix pluralization and add background fetch of metadata and relay lists
- Updated log message to use correct plurals for `owners`, `pubkey`, and related variables - Added background fetching of profile metadata, relay list metadata, and DM relays list using `SpiderFetch` in the goroutine - Modified `server.go` to import `"orly.dev/pkg/protocol/socketapi"` correctly and initialize `listeners` with the updated constructor
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"orly.dev/pkg/protocol/socketapi"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -15,7 +16,6 @@ import (
|
||||
"orly.dev/pkg/app/relay/publish"
|
||||
"orly.dev/pkg/interfaces/relay"
|
||||
"orly.dev/pkg/protocol/servemux"
|
||||
"orly.dev/pkg/protocol/socketapi"
|
||||
"orly.dev/pkg/utils/chk"
|
||||
"orly.dev/pkg/utils/context"
|
||||
"orly.dev/pkg/utils/log"
|
||||
@@ -90,15 +90,15 @@ func NewServer(sp *ServerParams, opts ...options.O) (s *Server, err error) {
|
||||
}
|
||||
serveMux := servemux.NewServeMux()
|
||||
s = &Server{
|
||||
Ctx: sp.Ctx,
|
||||
Cancel: sp.Cancel,
|
||||
relay: sp.Rl,
|
||||
mux: serveMux,
|
||||
options: op,
|
||||
listeners: publish.New(socketapi.New()),
|
||||
C: sp.C,
|
||||
Lists: new(Lists),
|
||||
Ctx: sp.Ctx,
|
||||
Cancel: sp.Cancel,
|
||||
relay: sp.Rl,
|
||||
mux: serveMux,
|
||||
options: op,
|
||||
C: sp.C,
|
||||
Lists: new(Lists),
|
||||
}
|
||||
s.listeners = publish.New(socketapi.New(s))
|
||||
go func() {
|
||||
if err := s.relay.Init(); chk.E(err) {
|
||||
s.Shutdown()
|
||||
|
||||
@@ -44,90 +44,92 @@ func (s *Server) Spider(noFetch ...bool) (err error) {
|
||||
// there is no OwnersPubkeys, so there is nothing to do.
|
||||
return
|
||||
}
|
||||
dontFetch := false
|
||||
if len(noFetch) > 0 && noFetch[0] {
|
||||
dontFetch = true
|
||||
}
|
||||
log.I.F("getting ownersFollowed")
|
||||
var ownersFollowed [][]byte
|
||||
if ownersFollowed, err = s.SpiderFetch(
|
||||
kind.FollowList, dontFetch, ownersPubkeys...,
|
||||
); chk.E(err) {
|
||||
return
|
||||
}
|
||||
log.I.F("getting followedFollows")
|
||||
var followedFollows [][]byte
|
||||
if followedFollows, err = s.SpiderFetch(
|
||||
kind.FollowList, dontFetch, ownersFollowed...,
|
||||
); chk.E(err) {
|
||||
return
|
||||
}
|
||||
log.I.F("getting ownersMuted")
|
||||
var ownersMuted [][]byte
|
||||
if ownersMuted, err = s.SpiderFetch(
|
||||
kind.MuteList, dontFetch, ownersPubkeys...,
|
||||
); chk.E(err) {
|
||||
return
|
||||
}
|
||||
// remove the ownersFollowed and ownersMuted items from the followedFollows
|
||||
// list
|
||||
filteredFollows := make([][]byte, 0, len(followedFollows))
|
||||
for _, follow := range followedFollows {
|
||||
found := false
|
||||
for _, owner := range ownersFollowed {
|
||||
if bytes.Equal(follow, owner) {
|
||||
found = true
|
||||
break
|
||||
go func() {
|
||||
dontFetch := false
|
||||
if len(noFetch) > 0 && noFetch[0] {
|
||||
dontFetch = true
|
||||
}
|
||||
log.I.F("getting ownersFollowed")
|
||||
var ownersFollowed [][]byte
|
||||
if ownersFollowed, err = s.SpiderFetch(
|
||||
kind.FollowList, dontFetch, ownersPubkeys...,
|
||||
); chk.E(err) {
|
||||
return
|
||||
}
|
||||
log.I.F("getting followedFollows")
|
||||
var followedFollows [][]byte
|
||||
if followedFollows, err = s.SpiderFetch(
|
||||
kind.FollowList, dontFetch, ownersFollowed...,
|
||||
); chk.E(err) {
|
||||
return
|
||||
}
|
||||
log.I.F("getting ownersMuted")
|
||||
var ownersMuted [][]byte
|
||||
if ownersMuted, err = s.SpiderFetch(
|
||||
kind.MuteList, dontFetch, ownersPubkeys...,
|
||||
); chk.E(err) {
|
||||
return
|
||||
}
|
||||
// remove the ownersFollowed and ownersMuted items from the followedFollows
|
||||
// list
|
||||
filteredFollows := make([][]byte, 0, len(followedFollows))
|
||||
for _, follow := range followedFollows {
|
||||
found := false
|
||||
for _, owner := range ownersFollowed {
|
||||
if bytes.Equal(follow, owner) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, owner := range ownersMuted {
|
||||
if bytes.Equal(follow, owner) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
filteredFollows = append(filteredFollows, follow)
|
||||
}
|
||||
}
|
||||
for _, owner := range ownersMuted {
|
||||
if bytes.Equal(follow, owner) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
followedFollows = filteredFollows
|
||||
own := "owner"
|
||||
if len(ownersPubkeys) > 1 {
|
||||
own = "owners"
|
||||
}
|
||||
if !found {
|
||||
filteredFollows = append(filteredFollows, follow)
|
||||
fol := "pubkey"
|
||||
if len(ownersFollowed) > 1 {
|
||||
fol = "pubkeys"
|
||||
}
|
||||
}
|
||||
followedFollows = filteredFollows
|
||||
own := "owner"
|
||||
if len(ownersPubkeys) > 1 {
|
||||
own = "owners"
|
||||
}
|
||||
fol := "pubkey"
|
||||
if len(ownersFollowed) > 1 {
|
||||
fol = "pubkeys"
|
||||
}
|
||||
folfol := "pubkey"
|
||||
if len(followedFollows) > 1 {
|
||||
folfol = "pubkeys"
|
||||
}
|
||||
mut := "pubkey"
|
||||
if len(ownersMuted) > 1 {
|
||||
mut = "pubkeys"
|
||||
}
|
||||
log.T.F(
|
||||
"found %d %s with a total of %d followed %s and %d followed's follows %s, and excluding %d owner muted %s",
|
||||
len(ownersPubkeys), own,
|
||||
len(ownersFollowed), fol,
|
||||
len(followedFollows), folfol,
|
||||
len(ownersMuted), mut,
|
||||
)
|
||||
// add the owners
|
||||
ownersFollowed = append(ownersFollowed, ownersPubkeys...)
|
||||
s.SetOwnersPubkeys(ownersPubkeys)
|
||||
s.SetOwnersFollowed(ownersFollowed)
|
||||
s.SetFollowedFollows(followedFollows)
|
||||
s.SetOwnersMuted(ownersMuted)
|
||||
// lastly, update users profile metadata and relay lists in the background
|
||||
if !dontFetch {
|
||||
go func() {
|
||||
everyone := append(ownersFollowed, followedFollows...)
|
||||
s.SpiderFetch(kind.ProfileMetadata, false, everyone...)
|
||||
s.SpiderFetch(kind.RelayListMetadata, false, everyone...)
|
||||
s.SpiderFetch(kind.DMRelaysList, false, everyone...)
|
||||
}()
|
||||
}
|
||||
folfol := "pubkey"
|
||||
if len(followedFollows) > 1 {
|
||||
folfol = "pubkeys"
|
||||
}
|
||||
mut := "pubkey"
|
||||
if len(ownersMuted) > 1 {
|
||||
mut = "pubkeys"
|
||||
}
|
||||
log.T.F(
|
||||
"found %d %s with a total of %d followed %s and %d followed's follows %s, and excluding %d owner muted %s",
|
||||
len(ownersPubkeys), own,
|
||||
len(ownersFollowed), fol,
|
||||
len(followedFollows), folfol,
|
||||
len(ownersMuted), mut,
|
||||
)
|
||||
// add the owners
|
||||
ownersFollowed = append(ownersFollowed, ownersPubkeys...)
|
||||
s.SetOwnersPubkeys(ownersPubkeys)
|
||||
s.SetOwnersFollowed(ownersFollowed)
|
||||
s.SetFollowedFollows(followedFollows)
|
||||
s.SetOwnersMuted(ownersMuted)
|
||||
// lastly, update users profile metadata and relay lists in the background
|
||||
if !dontFetch {
|
||||
go func() {
|
||||
everyone := append(ownersFollowed, followedFollows...)
|
||||
s.SpiderFetch(kind.ProfileMetadata, false, everyone...)
|
||||
s.SpiderFetch(kind.RelayListMetadata, false, everyone...)
|
||||
s.SpiderFetch(kind.DMRelaysList, false, everyone...)
|
||||
}()
|
||||
}
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"orly.dev/pkg/utils/chk"
|
||||
"orly.dev/pkg/utils/context"
|
||||
"orly.dev/pkg/utils/errorf"
|
||||
"orly.dev/pkg/utils/log"
|
||||
"sort"
|
||||
)
|
||||
|
||||
@@ -38,7 +37,6 @@ func (d *D) SaveEvent(c context.T, ev *event.E) (kc, vc int, err error) {
|
||||
DTag: t.Value(),
|
||||
}
|
||||
at := a.Marshal(nil)
|
||||
log.I.S(at)
|
||||
if idxs, err = GetIndexesFromFilter(
|
||||
&filter.F{
|
||||
Authors: tag.New(ev.Pubkey),
|
||||
|
||||
45
pkg/protocol/auth/check-privilege.go
Normal file
45
pkg/protocol/auth/check-privilege.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"orly.dev/pkg/encoders/event"
|
||||
"orly.dev/pkg/encoders/hex"
|
||||
"orly.dev/pkg/encoders/tag"
|
||||
)
|
||||
|
||||
func CheckPrivilege(authedPubkey []byte, ev *event.E) (privileged bool) {
|
||||
if ev.Kind.IsPrivileged() {
|
||||
if len(authedPubkey) == 0 {
|
||||
// this is a shortcut because none of the following
|
||||
// tests would return true.
|
||||
return
|
||||
}
|
||||
// authed users when auth is required must be present in the
|
||||
// event if it is privileged.
|
||||
authedIsAuthor := bytes.Equal(ev.Pubkey, authedPubkey)
|
||||
// if the authed pubkey matches the event author, it is
|
||||
// allowed.
|
||||
if !authedIsAuthor {
|
||||
// check whether one of the p (mention) tags is
|
||||
// present designating the authed pubkey, as this means
|
||||
// the author wants the designated pubkey to be able to
|
||||
// access the event. this is the case for nip-4, nip-44
|
||||
// DMs, and gift-wraps. The query would usually have
|
||||
// been for precisely a p tag with their pubkey.
|
||||
eTags := ev.Tags.GetAll(tag.New("p"))
|
||||
var hexAuthedKey []byte
|
||||
hex.EncAppend(hexAuthedKey, authedPubkey)
|
||||
var authedIsMentioned bool
|
||||
for _, e := range eTags.ToSliceOfTags() {
|
||||
if bytes.Equal(e.Value(), hexAuthedKey) {
|
||||
authedIsMentioned = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !authedIsMentioned {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
// corresponding handler method, generates a notice for errors or unknown types,
|
||||
// logs the notice, and writes it back to the listener if required.
|
||||
func (a *A) HandleMessage(msg []byte) {
|
||||
log.T.F("received message:\n%s", string(msg))
|
||||
var notice []byte
|
||||
var err error
|
||||
var t string
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package socketapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"github.com/dgraph-io/badger/v4"
|
||||
"orly.dev/pkg/encoders/envelopes/closedenvelope"
|
||||
@@ -9,9 +8,8 @@ import (
|
||||
"orly.dev/pkg/encoders/envelopes/eventenvelope"
|
||||
"orly.dev/pkg/encoders/envelopes/reqenvelope"
|
||||
"orly.dev/pkg/encoders/event"
|
||||
"orly.dev/pkg/encoders/hex"
|
||||
"orly.dev/pkg/encoders/tag"
|
||||
"orly.dev/pkg/interfaces/server"
|
||||
"orly.dev/pkg/protocol/auth"
|
||||
"orly.dev/pkg/utils/chk"
|
||||
"orly.dev/pkg/utils/context"
|
||||
"orly.dev/pkg/utils/log"
|
||||
@@ -91,39 +89,12 @@ func (a *A) HandleReq(
|
||||
if srv.AuthRequired() {
|
||||
var tmp event.S
|
||||
for _, ev := range events {
|
||||
if ev.Kind.IsPrivileged() {
|
||||
authedPubkey := a.Listener.AuthedPubkey()
|
||||
if len(authedPubkey) == 0 {
|
||||
// this is a shortcut because none of the following
|
||||
// tests would return true.
|
||||
continue
|
||||
}
|
||||
// authed users when auth is required must be present in the
|
||||
// event if it is privileged.
|
||||
authedIsAuthor := bytes.Equal(ev.Pubkey, authedPubkey)
|
||||
// if the authed pubkey matches the event author, it is
|
||||
// allowed.
|
||||
if !authedIsAuthor {
|
||||
// check whether one of the p (mention) tags is
|
||||
// present designating the authed pubkey, as this means
|
||||
// the author wants the designated pubkey to be able to
|
||||
// access the event. this is the case for nip-4, nip-44
|
||||
// DMs, and gift-wraps. The query would usually have
|
||||
// been for precisely a p tag with their pubkey.
|
||||
eTags := ev.Tags.GetAll(tag.New("p"))
|
||||
var hexAuthedKey []byte
|
||||
hex.EncAppend(hexAuthedKey, authedPubkey)
|
||||
var authedIsMentioned bool
|
||||
for _, e := range eTags.ToSliceOfTags() {
|
||||
if bytes.Equal(e.Value(), hexAuthedKey) {
|
||||
authedIsMentioned = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !authedIsMentioned {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if auth.CheckPrivilege(a.Listener.AuthedPubkey(), ev) {
|
||||
log.W.F(
|
||||
"not privileged %0x ev pubkey %0x",
|
||||
a.Listener.AuthedPubkey(), ev.Pubkey,
|
||||
)
|
||||
continue
|
||||
}
|
||||
tmp = append(tmp, ev)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"orly.dev/pkg/encoders/event"
|
||||
"orly.dev/pkg/encoders/filters"
|
||||
"orly.dev/pkg/interfaces/publisher"
|
||||
"orly.dev/pkg/interfaces/server"
|
||||
"orly.dev/pkg/protocol/auth"
|
||||
"orly.dev/pkg/protocol/ws"
|
||||
"orly.dev/pkg/utils/chk"
|
||||
"orly.dev/pkg/utils/log"
|
||||
@@ -57,11 +59,13 @@ type S struct {
|
||||
Mx sync.Mutex
|
||||
// Map is the map of subscribers and subscriptions from the websocket api.
|
||||
Map
|
||||
// Server is an interface to the server.
|
||||
Server server.I
|
||||
}
|
||||
|
||||
var _ publisher.I = &S{}
|
||||
|
||||
func New() (publisher *S) { return &S{Map: make(Map)} }
|
||||
func New(s server.I) (publisher *S) { return &S{Map: make(Map), Server: s} }
|
||||
|
||||
func (p *S) Type() (typeName string) { return Type }
|
||||
|
||||
@@ -98,6 +102,7 @@ func (p *S) Receive(msg publisher.Message) {
|
||||
return
|
||||
}
|
||||
p.Mx.Lock()
|
||||
defer p.Mx.Unlock()
|
||||
if subs, ok := p.Map[m.Listener]; !ok {
|
||||
subs = make(map[string]*filters.T)
|
||||
subs[m.Id] = m.Filters
|
||||
@@ -112,33 +117,25 @@ func (p *S) Receive(msg publisher.Message) {
|
||||
"added subscription %s for %s", m.Id, m.Listener.RealRemote(),
|
||||
)
|
||||
}
|
||||
p.Mx.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// Deliver sends an event to all subscribers whose filters match the event
|
||||
// Deliver processes and distributes an event to all matching subscribers based on their filter configurations.
|
||||
//
|
||||
// # Parameters
|
||||
//
|
||||
// - ev (*event.E): The event to deliver to matching subscribers
|
||||
// - ev (*event.E): The event to be delivered to subscribed clients.
|
||||
//
|
||||
// # Expected behaviour
|
||||
//
|
||||
// # Locks the mutex to synchronize access to subscriber data
|
||||
//
|
||||
// # Iterates over all websocket connections and their associated subscriptions
|
||||
//
|
||||
// # Checks if each subscription's filter matches the event being delivered
|
||||
//
|
||||
// # Creates an event envelope result for matching subscriptions
|
||||
//
|
||||
// # Writes the result to the corresponding websocket connection
|
||||
//
|
||||
// Logs details about event delivery and any errors encountered
|
||||
// Delivers the event to all subscribers whose filters match the event. It
|
||||
// applies authentication checks if required by the server, and skips delivery
|
||||
// for unauthenticated users when events are privileged.
|
||||
func (p *S) Deliver(ev *event.E) {
|
||||
log.T.F("delivering event %0x to subscribers", ev.Id)
|
||||
var err error
|
||||
p.Mx.Lock()
|
||||
defer p.Mx.Unlock()
|
||||
for w, subs := range p.Map {
|
||||
log.I.F("%v %s", subs, w.RealRemote())
|
||||
for id, subscriber := range subs {
|
||||
@@ -149,17 +146,21 @@ func (p *S) Deliver(ev *event.E) {
|
||||
if !subscriber.Match(ev) {
|
||||
continue
|
||||
}
|
||||
var res *eventenvelope.Result
|
||||
if res, err = eventenvelope.NewResultWith(id, ev); chk.E(err) {
|
||||
continue
|
||||
if p.Server.AuthRequired() {
|
||||
if auth.CheckPrivilege(w.AuthedPubkey(), ev) {
|
||||
continue
|
||||
}
|
||||
var res *eventenvelope.Result
|
||||
if res, err = eventenvelope.NewResultWith(id, ev); chk.E(err) {
|
||||
continue
|
||||
}
|
||||
if err = res.Write(w); chk.E(err) {
|
||||
continue
|
||||
}
|
||||
log.T.F("dispatched event %0x to subscription %s", ev.Id, id)
|
||||
}
|
||||
if err = res.Write(w); chk.E(err) {
|
||||
continue
|
||||
}
|
||||
log.T.F("dispatched event %0x to subscription %s", ev.Id, id)
|
||||
}
|
||||
}
|
||||
p.Mx.Unlock()
|
||||
}
|
||||
|
||||
// removeSubscriberId removes a specific subscription from a subscriber
|
||||
|
||||
Reference in New Issue
Block a user