tinyrelayfile
tinyrelay/internal/replication/delivery.go/

internal/replication/delivery.go raw
1package replication
2
3import (
4 "context"
5 "errors"
6 "fmt"
7
8 "github.com/FelineStateMachine/tinyrelay/internal/event"
9 "github.com/FelineStateMachine/tinyrelay/internal/policy"
10 "github.com/FelineStateMachine/tinyrelay/internal/storage"
11)
12
13type DeliveryHandler func(context.Context, storage.Intent) error
14
15func NewDeliveryHandler(store *storage.Store, transport DeliveryTransport) DeliveryHandler {
16 return func(ctx context.Context, intent storage.Intent) error {
17 return deliver(ctx, store, transport, intent)
18 }
19}
20
21func deliver(ctx context.Context, store *storage.Store, transport DeliveryTransport, intent storage.Intent) error {
22 if err := ValidateIntent(intent); err != nil {
23 return err
24 }
25 result, err := store.Query(ctx, event.Filter{IDs: []string{intent.EventID}, Tags: map[string][]string{}}, storage.QueryOptions{Now: 0, Access: storage.Access{All: true}, Limit: 1})
26 if err != nil {
27 return fmt.Errorf("replication: load delivery event: %w", err)
28 }
29 if len(result.Events) == 0 {
30 return nil
31 }
32 e := result.Events[0]
33 private, privateErr := privateRepository(ctx, store, e)
34 if privateErr != nil {
35 return fmt.Errorf("replication: check repository privacy: %w", privateErr)
36 }
37 if privateKind(e.Kind) || hasProtectedTag(e) || private {
38 return nil
39 }
40 if e.Kind != 10002 {
41 if relayList, err := authorRelayList(ctx, store, e); err != nil {
42 return fmt.Errorf("replication: load author relay list: %w", err)
43 } else if relayList != nil {
44 if err := sendAccepted(ctx, transport, intent.Target, *relayList); err != nil {
45 return err
46 }
47 }
48 }
49 return sendAccepted(ctx, transport, intent.Target, e)
50}
51
52func privateRepository(ctx context.Context, store *storage.Store, e event.Event) (bool, error) {
53 return policy.PrivateRepository(ctx, store, e)
54}
55
56func authorRelayList(ctx context.Context, store *storage.Store, e event.Event) (*event.Event, error) {
57 result, err := store.Query(ctx, event.Filter{Authors: []string{e.PubKey}, Kinds: []int{10002}, Tags: map[string][]string{}}, storage.QueryOptions{Now: 0, Access: storage.Access{All: true}, Limit: 1})
58 if err != nil {
59 return nil, err
60 }
61 for _, candidate := range result.Events {
62 if candidate.Kind == 10002 && !privateKind(candidate.Kind) && !hasProtectedTag(candidate) {
63 return &candidate, nil
64 }
65 }
66 return nil, nil
67}
68
69func sendAccepted(ctx context.Context, transport DeliveryTransport, target string, e event.Event) error {
70 response, err := transport.Send(ctx, target, e)
71 if err != nil {
72 return fmt.Errorf("replication: send event: %w", err)
73 }
74 if response.Accepted || isDuplicate(response.Message) {
75 return nil
76 }
77 message := response.Message
78 if message == "" {
79 message = "target rejected event"
80 }
81 return errors.New(message)
82}
83
84func hasProtectedTag(e event.Event) bool {
85 for _, tag := range e.Tags {
86 if len(tag) > 0 && tag[0] == "-" {
87 return true
88 }
89 }
90 return false
91}
92
93func isDuplicate(message string) bool {
94 const prefix = "duplicate:"
95 return len(message) >= len(prefix) && message[:len(prefix)] == prefix
96}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs