1package daemon23import (4 "context"5 "encoding/json"6 "fmt"78 "github.com/FelineStateMachine/tinyrelay/internal/event"9 "github.com/FelineStateMachine/tinyrelay/internal/policy"10 "github.com/FelineStateMachine/tinyrelay/internal/replication"11)1213func (t *Tenant) reconcileAutomaticInbox(ctx context.Context, previous, current policy.Policy) error {14 if t.replication == nil {15 return nil16 }17 jobs, err := t.replication.ListJobs(ctx)18 if err != nil {19 return fmt.Errorf("daemon: list inbox jobs: %w", err)20 }21 jobID := "source-" + t.meta.ID22 var automatic *replication.JobSpec23 var explicit bool24 for _, job := range jobs {25 if job.ID != jobID {26 continue27 }28 if job.DiscoverPubKey != "" {29 copy := job30 automatic = ©31 } else {32 explicit = true33 }34 }35 if !current.Inbox.Targeted {36 if automatic == nil {37 return nil38 }39 return t.replication.RemoveJob(ctx, jobID)40 }41 if automatic == nil && explicit {42 return nil43 }44 owner := current.Owner45 kinds, err := t.inboxAllowedKinds(ctx, current)46 if err != nil {47 return err48 }49 filter := map[string]any{"#p": []string{owner}}50 if len(kinds) > 0 {51 filter["kinds"] = kinds52 }53 raw, err := json.Marshal(filter)54 if err != nil {55 return fmt.Errorf("daemon: encode inbox filter: %w", err)56 }57 desired := replication.JobSpec{ID: jobID, Kind: replication.JobPull, Filter: string(raw), Every: 1, DiscoverPubKey: owner}58 if automatic != nil && sameInboxJob(*automatic, desired) {59 return nil60 }61 if automatic != nil {62 if err := t.replication.RemoveJob(ctx, jobID); err != nil {63 return fmt.Errorf("daemon: replace inbox job: %w", err)64 }65 }66 if err := t.replication.AddJob(ctx, desired); err != nil {67 return fmt.Errorf("daemon: save inbox job: %w", err)68 }69 return nil70}7172func (t *Tenant) inboxAllowedKinds(ctx context.Context, p policy.Policy) ([]int, error) {73 if len(p.AllowedKinds) > 0 {74 return append([]int(nil), p.AllowedKinds...), nil75 }76 rows, err := t.store.DB().QueryContext(ctx, `SELECT kind FROM community_kind_rules WHERE rule='allow' ORDER BY kind`)77 if err != nil {78 return nil, fmt.Errorf("daemon: read inbox kind rules: %w", err)79 }80 defer rows.Close()81 var kinds []int82 for rows.Next() {83 var kind int84 if err := rows.Scan(&kind); err != nil {85 return nil, err86 }87 kinds = append(kinds, kind)88 }89 return kinds, rows.Err()90}9192func inboxJobOwner(job replication.JobSpec) string {93 filter, err := event.ParseFilter([]byte(job.Filter))94 if err != nil || len(filter.Tags["p"]) == 0 {95 return ""96 }97 return filter.Tags["p"][0]98}99100func sameInboxJob(a, b replication.JobSpec) bool {101 return a.ID == b.ID && a.Kind == b.Kind && a.Filter == b.Filter && a.Every == b.Every && a.DiscoverPubKey == b.DiscoverPubKey && len(a.Relays) == 0 && len(b.Relays) == 0102}